~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/generic/dataengines/share/shareprovider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright 2010 Artur Duque de Souza <asouza@kde.org>                  *
 
3
 *                                                                         *
 
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.                                   *
 
8
 *                                                                         *
 
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.                          *
 
13
 *                                                                         *
 
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
 ***************************************************************************/
 
19
 
 
20
#include <QFile>
 
21
#include <QXmlStreamReader>
 
22
 
 
23
#include <krandom.h>
 
24
#include <KDebug>
 
25
#include <KDE/KIO/MimetypeJob>
 
26
#include <KDE/KIO/FileJob>
 
27
 
 
28
#include "shareprovider.h"
 
29
#include "share_package.h"
 
30
 
 
31
Plasma::PackageStructure::Ptr ShareProvider::m_packageStructure(0);
 
32
 
 
33
 
 
34
ShareProvider::ShareProvider(QObject *parent)
 
35
    : QObject(parent), m_isBlob(false), m_isPost(true)
 
36
{
 
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();
 
41
}
 
42
 
 
43
QString ShareProvider::method() const
 
44
{
 
45
    if (!m_isPost) {
 
46
        return QString("GET");
 
47
    }
 
48
    return QString("POST");
 
49
}
 
50
 
 
51
void ShareProvider::setMethod(const QString &method)
 
52
{
 
53
    if (method == "GET") {
 
54
        m_isPost = false;
 
55
    } else {
 
56
        m_isPost = true;
 
57
    }
 
58
}
 
59
 
 
60
KUrl ShareProvider::url() const
 
61
{
 
62
    // the url that is set in this provider
 
63
    return m_url;
 
64
}
 
65
 
 
66
void ShareProvider::setUrl(const QString &url)
 
67
{
 
68
    // set the provider's url
 
69
    m_url = url;
 
70
    m_service = url;
 
71
}
 
72
 
 
73
QString ShareProvider::parseXML(const QString &key, const QString &data)
 
74
{
 
75
    // this method helps plugins to parse results from webpages
 
76
    QXmlStreamReader xml(data);
 
77
    if (xml.hasError()) {
 
78
        return QString();
 
79
    }
 
80
 
 
81
    while (!xml.atEnd()) {
 
82
        xml.readNext();
 
83
 
 
84
        if (xml.name() == key) {
 
85
            QString url = xml.readElementText();
 
86
            return url;
 
87
        }
 
88
    }
 
89
 
 
90
    return QString();
 
91
}
 
92
 
 
93
void ShareProvider::addPostItem(const QString &key, const QString &value,
 
94
                                const QString &contentType)
 
95
{
 
96
    if (!m_isPost)
 
97
        return;
 
98
 
 
99
    // add a pair <item,value> in a post form
 
100
    QByteArray str;
 
101
    QString length = QString("%1").arg(value.length());
 
102
 
 
103
    str += "--";
 
104
    str += m_boundary;
 
105
    str += "\r\n";
 
106
 
 
107
    if (!key.isEmpty()) {
 
108
        str += "Content-Disposition: form-data; name=\"";
 
109
        str += key.toAscii();
 
110
        str += "\"\r\n";
 
111
    }
 
112
 
 
113
    if (!contentType.isEmpty()) {
 
114
        str += "Content-Type: " + QByteArray(contentType.toAscii());
 
115
        str += "\r\n";
 
116
        str += "Mime-version: 1.0 ";
 
117
        str += "\r\n";
 
118
    }
 
119
 
 
120
    str += "Content-Length: ";
 
121
    str += length.toAscii();
 
122
    str += "\r\n\r\n";
 
123
    str += value.toUtf8();
 
124
 
 
125
    m_buffer.append(str);
 
126
    m_buffer.append("\r\n");
 
127
}
 
128
 
 
129
void ShareProvider::addPostFile(const QString &contentKey, const QString &content)
 
130
{
 
131
    // add a file in a post form (gets it using KIO)
 
132
    m_contentKey = contentKey;
 
133
    m_content = content;
 
134
 
 
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
 
137
    // three use cases:
 
138
    // 1 - just text
 
139
    // 2 - a file that is a text
 
140
    // 3 - other kind of files (images, pdf, etc..)
 
141
    //
 
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.
 
145
    KUrl url(m_content);
 
146
 
 
147
    KIO::MimetypeJob *mjob = KIO::mimetype(url);
 
148
    if (!mjob->exec()) {
 
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();
 
154
        return;
 
155
    }
 
156
 
 
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"));
 
163
        return;
 
164
    }
 
165
 
 
166
    // If it's not plain text then we should handle it later
 
167
    if (m_mimetype != "text/plain") {
 
168
        m_isBlob = true;
 
169
    }
 
170
 
 
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*)));
 
174
}
 
175
 
 
176
void ShareProvider::openFile(KIO::Job *job)
 
177
{
 
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&)));
 
183
}
 
184
 
 
185
void ShareProvider::finishedContentData(KIO::Job *job, const QByteArray &data)
 
186
{
 
187
    Q_UNUSED(job);
 
188
    if (data.length() == 0) {
 
189
        error(i18n("It was not possible to read the selected file"));
 
190
        return;
 
191
    }
 
192
 
 
193
    if (!m_isBlob) {
 
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();
 
198
        return;
 
199
    }
 
200
 
 
201
    // Add the special http post stuff with the content of the file
 
202
    QByteArray str;
 
203
    const QString fileSize = QString("%1").arg(data.size());
 
204
    str += "--";
 
205
    str += m_boundary;
 
206
    str += "\r\n";
 
207
    str += "Content-Disposition: form-data; name=\"";
 
208
    str += m_contentKey.toAscii();
 
209
    str += "\"; ";
 
210
    str += "filename=\"";
 
211
    str += QFile::encodeName(KUrl(m_content).fileName()).replace(".tmp", ".jpg");
 
212
    str += "\"\r\n";
 
213
    str += "Content-Length: ";
 
214
    str += fileSize.toAscii();
 
215
    str += "\r\n";
 
216
    str += "Content-Type: ";
 
217
    str +=  m_mimetype.toAscii();
 
218
    str += "\r\n\r\n";
 
219
 
 
220
    m_buffer.append(str);
 
221
    m_buffer.append(data);
 
222
    m_buffer.append("\r\n");
 
223
 
 
224
    // tell the world that we are ready to publish
 
225
    emit readyToPublish();
 
226
}
 
227
 
 
228
void ShareProvider::readPublishData(KIO::Job *job, const QByteArray &data)
 
229
{
 
230
    Q_UNUSED(job);
 
231
    m_data.append(data);
 
232
}
 
233
 
 
234
void ShareProvider::finishedPublish(KJob *job)
 
235
{
 
236
    Q_UNUSED(job);
 
237
    if (m_data.length() == 0) {
 
238
        error(i18n("Service was not available"));
 
239
        return;
 
240
    }
 
241
 
 
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));
 
245
}
 
246
 
 
247
void ShareProvider::finishHeader()
 
248
{
 
249
    QByteArray str;
 
250
    str += "--";
 
251
    str += m_boundary;
 
252
    str += "--";
 
253
    m_buffer.append(str);
 
254
}
 
255
 
 
256
void ShareProvider::addQueryItem(const QString &key, const QString &value)
 
257
{
 
258
    // just add the item to the query's URL
 
259
    m_url.addQueryItem(key, value);
 
260
}
 
261
 
 
262
void ShareProvider::publish()
 
263
{
 
264
    if (m_url == "") {
 
265
        emit finishedError(i18n("You must specify a URL for this service"));
 
266
    }
 
267
 
 
268
    // clear the result data before publishing
 
269
    m_data.clear();
 
270
 
 
271
    // finish the http form
 
272
    if (m_isBlob) {
 
273
        finishHeader();
 
274
    }
 
275
 
 
276
    // Multipart is used to upload files
 
277
    KIO::TransferJob *tf;
 
278
    if (m_isBlob) {
 
279
        tf = KIO::http_post(m_service, m_buffer, KIO::HideProgressInfo);
 
280
        tf->addMetaData("content-type","Content-Type: multipart/form-data; boundary=" + m_boundary);
 
281
    } else {
 
282
        if (m_isPost) {
 
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");
 
286
        } else {
 
287
            QString url = QString("%1?%2").arg(m_service.url(), QString(m_url.encodedQuery()));
 
288
            tf = KIO::get(url);
 
289
        }
 
290
    }
 
291
 
 
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&)));
 
297
}
 
298
 
 
299
void ShareProvider::redirected(KIO::Job *job, const KUrl &to)
 
300
{
 
301
    Q_UNUSED(job)
 
302
    const QUrl toUrl(to);
 
303
    const QUrl serviceUrl(m_service);
 
304
 
 
305
    const QString toString(toUrl.toString(QUrl::StripTrailingSlash));
 
306
    const QString serviceString(serviceUrl.toString(QUrl::StripTrailingSlash));
 
307
 
 
308
    if (toString == serviceString) {
 
309
        return;
 
310
    }
 
311
 
 
312
    emit handleRedirection(toString);
 
313
}
 
314
 
 
315
void ShareProvider::success(const QString &url)
 
316
{
 
317
    // notify the service that it worked and the result url
 
318
    emit finished(url);
 
319
}
 
320
 
 
321
void ShareProvider::error(const QString &msg)
 
322
{
 
323
    // notify the service that it didnt work and the error msg
 
324
    emit finishedError(msg);
 
325
}
 
326
 
 
327
Plasma::PackageStructure::Ptr ShareProvider::packageStructure()
 
328
{
 
329
    if (!m_packageStructure) {
 
330
        m_packageStructure = new SharePackage();
 
331
    }
 
332
    return m_packageStructure;
 
333
}
 
334
 
 
335
#include "shareprovider.moc"