1
/***************************************************************************
2
* Copyright 2010 Artur Duque de Souza <asouza@kde.org> *
4
* This program is free software; you can redistribute it and/or modify *
5
* it under the terms of the GNU General Public License as published by *
6
* the Free Software Foundation; either version 2 of the License, or *
7
* (at your option) any later version. *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License for more details. *
14
* You should have received a copy of the GNU General Public License *
15
* along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
18
***************************************************************************/
21
#include <QXmlStreamReader>
25
#include <KDE/KIO/MimetypeJob>
26
#include <KDE/KIO/FileJob>
28
#include "shareprovider.h"
29
#include "share_package.h"
31
Plasma::PackageStructure::Ptr ShareProvider::m_packageStructure(0);
34
ShareProvider::ShareProvider(QObject *parent)
35
: QObject(parent), m_isBlob(false), m_isPost(true)
37
// Just make the boundary random part long enough to be sure
38
// it's not inside one of the arguments that we are sending
39
m_boundary = "----------";
40
m_boundary += KRandom::randomString(55).toAscii();
43
QString ShareProvider::method() const
46
return QString("GET");
48
return QString("POST");
51
void ShareProvider::setMethod(const QString &method)
53
if (method == "GET") {
60
KUrl ShareProvider::url() const
62
// the url that is set in this provider
66
void ShareProvider::setUrl(const QString &url)
68
// set the provider's url
73
QString ShareProvider::parseXML(const QString &key, const QString &data)
75
// this method helps plugins to parse results from webpages
76
QXmlStreamReader xml(data);
81
while (!xml.atEnd()) {
84
if (xml.name() == key) {
85
QString url = xml.readElementText();
93
void ShareProvider::addPostItem(const QString &key, const QString &value,
94
const QString &contentType)
99
// add a pair <item,value> in a post form
101
QString length = QString("%1").arg(value.length());
107
if (!key.isEmpty()) {
108
str += "Content-Disposition: form-data; name=\"";
109
str += key.toAscii();
113
if (!contentType.isEmpty()) {
114
str += "Content-Type: " + QByteArray(contentType.toAscii());
116
str += "Mime-version: 1.0 ";
120
str += "Content-Length: ";
121
str += length.toAscii();
123
str += value.toUtf8();
125
m_buffer.append(str);
126
m_buffer.append("\r\n");
129
void ShareProvider::addPostFile(const QString &contentKey, const QString &content)
131
// add a file in a post form (gets it using KIO)
132
m_contentKey = contentKey;
135
// we expect either text or an URL of a file. The file can be a text file
136
// that is an exception that we handle in this case. So we have basically
139
// 2 - a file that is a text
140
// 3 - other kind of files (images, pdf, etc..)
142
// The applet using this engine must ensure that the provider selected
143
// supports the file format that is added here as a parameter, otherwise
144
// it will return as an error later in the process.
147
KIO::MimetypeJob *mjob = KIO::mimetype(url);
149
// it's not a file - usually this happens when we are
150
// just sharing plain text, so add the content and publish it
151
addPostItem(m_contentKey, m_content, "text/plain");
152
addQueryItem(m_contentKey, m_content);
153
emit readyToPublish();
157
// It's a valid file because there were no errors
158
m_mimetype = mjob->mimetype();
159
if (m_mimetype.isEmpty()) {
160
// if we ourselves can't determine the mime of the file,
161
// very unlikely the remote site will be able to identify it
162
error(i18n("Could not detect the file's mimetype"));
166
// If it's not plain text then we should handle it later
167
if (m_mimetype != "text/plain") {
171
// try to open the file
172
KIO::FileJob *fjob = KIO::open(KUrl(m_content), QIODevice::ReadOnly);
173
connect(fjob, SIGNAL(open(KIO::Job*)), this, SLOT(openFile(KIO::Job*)));
176
void ShareProvider::openFile(KIO::Job *job)
178
// finished opening the file, now try to read it's content
179
KIO::FileJob *fjob = static_cast<KIO::FileJob*>(job);
180
fjob->read(fjob->size());
181
connect(fjob, SIGNAL(data(KIO::Job*, const QByteArray&)),
182
this, SLOT(finishedContentData(KIO::Job*, const QByteArray&)));
185
void ShareProvider::finishedContentData(KIO::Job *job, const QByteArray &data)
188
if (data.length() == 0) {
189
error(i18n("It was not possible to read the selected file"));
194
// it's just text and we can return here using data()
195
addPostItem(m_contentKey, data.data(), "text/plain");
196
addQueryItem(m_contentKey, data.data());
197
emit readyToPublish();
201
// Add the special http post stuff with the content of the file
203
const QString fileSize = QString("%1").arg(data.size());
207
str += "Content-Disposition: form-data; name=\"";
208
str += m_contentKey.toAscii();
210
str += "filename=\"";
211
str += QFile::encodeName(KUrl(m_content).fileName()).replace(".tmp", ".jpg");
213
str += "Content-Length: ";
214
str += fileSize.toAscii();
216
str += "Content-Type: ";
217
str += m_mimetype.toAscii();
220
m_buffer.append(str);
221
m_buffer.append(data);
222
m_buffer.append("\r\n");
224
// tell the world that we are ready to publish
225
emit readyToPublish();
228
void ShareProvider::readPublishData(KIO::Job *job, const QByteArray &data)
234
void ShareProvider::finishedPublish(KJob *job)
237
if (m_data.length() == 0) {
238
error(i18n("Service was not available"));
242
// process data. should be interpreted by the plugin.
243
// plugin must call the right slots after processing the data.
244
emit handleResultData(QString(m_data));
247
void ShareProvider::finishHeader()
253
m_buffer.append(str);
256
void ShareProvider::addQueryItem(const QString &key, const QString &value)
258
// just add the item to the query's URL
259
m_url.addQueryItem(key, value);
262
void ShareProvider::publish()
265
emit finishedError(i18n("You must specify a URL for this service"));
268
// clear the result data before publishing
271
// finish the http form
276
// Multipart is used to upload files
277
KIO::TransferJob *tf;
279
tf = KIO::http_post(m_service, m_buffer, KIO::HideProgressInfo);
280
tf->addMetaData("content-type","Content-Type: multipart/form-data; boundary=" + m_boundary);
283
tf = KIO::http_post(m_service,
284
m_url.encodedQuery(), KIO::HideProgressInfo);
285
tf->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded");
287
QString url = QString("%1?%2").arg(m_service.url(), QString(m_url.encodedQuery()));
292
connect(tf, SIGNAL(data(KIO::Job*, const QByteArray&)),
293
this, SLOT(readPublishData(KIO::Job*, const QByteArray&)));
294
connect(tf, SIGNAL(result(KJob*)), this, SLOT(finishedPublish(KJob*)));
295
connect(tf, SIGNAL(redirection(KIO::Job*, const KUrl&)),
296
this, SLOT(redirected(KIO::Job*, const KUrl&)));
299
void ShareProvider::redirected(KIO::Job *job, const KUrl &to)
302
const QUrl toUrl(to);
303
const QUrl serviceUrl(m_service);
305
const QString toString(toUrl.toString(QUrl::StripTrailingSlash));
306
const QString serviceString(serviceUrl.toString(QUrl::StripTrailingSlash));
308
if (toString == serviceString) {
312
emit handleRedirection(toString);
315
void ShareProvider::success(const QString &url)
317
// notify the service that it worked and the result url
321
void ShareProvider::error(const QString &msg)
323
// notify the service that it didnt work and the error msg
324
emit finishedError(msg);
327
Plasma::PackageStructure::Ptr ShareProvider::packageStructure()
329
if (!m_packageStructure) {
330
m_packageStructure = new SharePackage();
332
return m_packageStructure;
335
#include "shareprovider.moc"