File indexing completed on 2025-01-05 03:53:37

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-03-22
0007  * Description : a Iface C++ interface
0008  *
0009  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2011      by Alexandre Mendes <alex dot mendes1988 at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "mediawiki_upload.h"
0017 
0018 // Qt includes
0019 
0020 #include <QFile>
0021 #include <QStringList>
0022 #include <QTimer>
0023 #include <QUrlQuery>
0024 #include <QXmlStreamReader>
0025 #include <QNetworkAccessManager>
0026 #include <QNetworkCookie>
0027 #include <QNetworkReply>
0028 #include <QNetworkRequest>
0029 
0030 // Local includes
0031 
0032 #include "mediawiki_job_p.h"
0033 #include "mediawiki_iface.h"
0034 
0035 namespace MediaWiki
0036 {
0037 
0038 class Q_DECL_HIDDEN UploadPrivate : public JobPrivate
0039 {
0040 public:
0041 
0042     explicit UploadPrivate(Iface& MediaWiki)
0043         : JobPrivate(MediaWiki),
0044           file(nullptr)
0045     {
0046     }
0047 
0048     static int error(const QString& error)
0049     {
0050         QString temp = error;
0051         int ret      = 0;
0052         QStringList list;
0053         list    << QStringLiteral("internalerror")
0054                 << QStringLiteral("uploaddisabled")
0055                 << QStringLiteral("invalidsessionkey")
0056                 << QStringLiteral("badaccessgroups")
0057                 << QStringLiteral("missingparam")
0058                 << QStringLiteral("mustbeloggedin")
0059                 << QStringLiteral("fetchfileerror")
0060                 << QStringLiteral("nomodule")
0061                 << QStringLiteral("emptyfile")
0062                 << QStringLiteral("filetypemissing")
0063                 << QStringLiteral("filenametooshort")
0064                 << QStringLiteral("overwrite")
0065                 << QStringLiteral("stashfailed");
0066 
0067         ret = list.indexOf(temp.remove(QChar::fromLatin1('-')));
0068 
0069         if (ret == -1)
0070         {
0071             ret = 0;
0072         }
0073 
0074         return  ret + (int)Upload::InternalError ;
0075     }
0076 
0077     QIODevice* file;
0078     QString    filename;
0079     QString    comment;
0080     QString    text;
0081     QString    token;
0082 };
0083 
0084 Upload::Upload(Iface& MediaWiki, QObject* const parent)
0085     : Job(*new UploadPrivate(MediaWiki), parent)
0086 {
0087 }
0088 
0089 Upload::~Upload()
0090 {
0091 }
0092 
0093 void Upload::setFilename(const QString& param)
0094 {
0095     Q_D(Upload);
0096     d->filename = param;
0097 }
0098 
0099 void Upload::setFile(QIODevice* const file)
0100 {
0101     Q_D(Upload);
0102     d->file = file;
0103 }
0104 
0105 void Upload::setComment(const QString& param)
0106 {
0107     Q_D(Upload);
0108     d->comment = param;
0109 }
0110 
0111 void Upload::setText(const QString& text)
0112 {
0113     Q_D(Upload);
0114     d->text = text;
0115 }
0116 
0117 void Upload::start()
0118 {
0119     Q_D(Upload);
0120 
0121     QueryInfo* const info = new QueryInfo(d->MediaWiki, this);
0122     info->setPageName(QStringLiteral("File:") + d->filename);
0123     info->setToken(QStringLiteral("tokens"));
0124 
0125     connect(info, SIGNAL(page(Page)),
0126             this, SLOT(doWorkSendRequest(Page)));
0127 
0128     info->start();
0129 }
0130 
0131 void Upload::doWorkSendRequest(const Page& page)
0132 {
0133     Q_D(Upload);
0134 
0135     QString token        = page.pageEditToken();
0136     d->token             = token;
0137 
0138     // Get the extension
0139 
0140     QStringList filename = d->filename.split(QChar::fromLatin1('.'));
0141     QString extension    = filename.at(filename.size()-1);
0142 
0143     if      (extension == QLatin1String("jpg"))
0144     {
0145         extension = QStringLiteral("jpeg");
0146     }
0147     else if (extension == QLatin1String("svg"))
0148     {
0149         extension += QStringLiteral("+xml");
0150     }
0151 
0152     QUrl url = d->MediaWiki.url();
0153     QUrlQuery query;
0154     query.addQueryItem(QStringLiteral("action"), QStringLiteral("upload"));
0155     query.addQueryItem(QStringLiteral("format"), QStringLiteral("xml"));
0156     url.setQuery(query);
0157 
0158     // Add the cookies
0159 
0160     QByteArray cookie = "";
0161     QList<QNetworkCookie> MediaWikiCookies = d->manager->cookieJar()->cookiesForUrl(d->MediaWiki.url());
0162 
0163     for (int i = 0 ; i < MediaWikiCookies.size() ; ++i)
0164     {
0165         cookie += MediaWikiCookies.at(i).toRawForm(QNetworkCookie::NameAndValueOnly);
0166         cookie += ';';
0167     }
0168 
0169     // Set the request
0170 
0171     QNetworkRequest request(url);
0172     request.setRawHeader("User-Agent", d->MediaWiki.userAgent().toUtf8());
0173     request.setRawHeader("Accept-Charset", "utf-8");
0174 
0175     QByteArray boundary = "-----------------------------15827188141577679942014851228";
0176     request.setRawHeader("Content-Type", "multipart/form-data; boundary="  + boundary);
0177     request.setRawHeader("Cookie", cookie);
0178 
0179     // send data
0180 
0181     boundary = "--" + boundary + "\r\n";
0182     QByteArray out = boundary;
0183 
0184     // ignore warnings
0185 
0186     out += "Content-Disposition: form-data; name=\"ignorewarnings\"\r\n\r\n";
0187     out += "true\r\n";
0188     out += boundary;
0189 
0190     // filename
0191 
0192     out += "Content-Disposition: form-data; name=\"filename\"\r\n\r\n";
0193     out += d->filename.toUtf8();
0194     out += "\r\n";
0195     out += boundary;
0196 
0197     // comment
0198 
0199     if (!d->comment.isEmpty())
0200     {
0201         out += "Content-Disposition: form-data; name=\"comment\"\r\n\r\n";
0202         out += d->comment.toUtf8();
0203         out += "\r\n";
0204         out += boundary;
0205     }
0206 
0207     // token
0208 
0209     out += "Content-Disposition: form-data; name=\"token\"\r\n\r\n";
0210     out += d->token.toUtf8();
0211     out += "\r\n";
0212     out += boundary;
0213 
0214     // the actual file
0215 
0216     out += "Content-Disposition: form-data; name=\"file\"; filename=\"";
0217     out += d->filename.toUtf8();
0218     out += "\"\r\n";
0219     out += "Content-Type: image/";
0220     out += extension.toUtf8();
0221     out += "\r\n\r\n";
0222     out += d->file->readAll();
0223     out += "\r\n";
0224     out += boundary;
0225 
0226     // description page
0227 
0228     out += "Content-Disposition: form-data; name=\"text\"\r\n";
0229     out += "Content-Type: text/plain\r\n\r\n";
0230     out += d->text.toUtf8();
0231     out += "\r\n";
0232     out += boundary.mid(0, boundary.length() - 2);
0233     out += "--\r\n";
0234 
0235     d->reply = d->manager->post(request, out);
0236     connectReply();
0237 
0238     connect(d->reply, SIGNAL(finished()),
0239             this, SLOT(doWorkProcessReply()));
0240 }
0241 
0242 void Upload::doWorkProcessReply()
0243 {
0244     Q_D(Upload);
0245 
0246     disconnect(d->reply, SIGNAL(finished()),
0247                this, SLOT(doWorkProcessReply()));
0248 
0249     if (d->reply->error() != QNetworkReply::NoError)
0250     {
0251         this->setError(this->NetworkError);
0252         d->reply->close();
0253         d->reply->deleteLater();
0254 
0255         emitResult();
0256         return;
0257     }
0258 
0259     QXmlStreamReader reader(d->reply);
0260 
0261     while (!reader.atEnd() && !reader.hasError())
0262     {
0263         QXmlStreamReader::TokenType token = reader.readNext();
0264 
0265         if      (token == QXmlStreamReader::StartElement)
0266         {
0267             QXmlStreamAttributes attrs = reader.attributes();
0268 
0269             if      (reader.name() == QLatin1String("upload"))
0270             {
0271                 if (attrs.value(QStringLiteral("result")).toString() == QLatin1String("Success"))
0272                 {
0273                     this->setError(KJob::NoError);
0274                 }
0275             }
0276             else if (reader.name() == QLatin1String("error"))
0277             {
0278                 this->setErrorText(attrs.value( QStringLiteral("info")).toString());
0279                 this->setError(UploadPrivate::error(attrs.value(QStringLiteral("code")).toString()));
0280             }
0281         }
0282         else if ((token          == QXmlStreamReader::Invalid) &&
0283                  (reader.error() != QXmlStreamReader::PrematureEndOfDocumentError))
0284         {
0285             this->setError(this->XmlError);
0286         }
0287     }
0288 
0289     d->reply->close();
0290     d->reply->deleteLater();
0291 
0292     emitResult();
0293 }
0294 
0295 } // namespace MediaWiki
0296 
0297 #include "moc_mediawiki_upload.cpp"