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"