File indexing completed on 2024-03-24 16:13:25

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