~ubuntu-branches/ubuntu/saucy/digikam/saucy

« back to all changes in this revision

Viewing changes to extra/kipi-plugins/picasawebexport/picasawebtalker.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer, Rohan Garg, Philip Muškovac, Felix Geyer
  • Date: 2011-09-23 18:18:55 UTC
  • mfrom: (1.2.36 upstream)
  • Revision ID: package-import@ubuntu.com-20110923181855-ifs67wxkugshev9k
Tags: 2:2.1.1-0ubuntu1
[ Rohan Garg ]
* New upstream release (LP: #834190)
  - debian/control
    + Build with libqtwebkit-dev
 - debian/kipi-plugins-common
    + Install libkvkontakte required by kipi-plugins
 - debian/digikam
    + Install panoramagui

[ Philip Muškovac ]
* New upstream release
  - debian/control:
    + Add libcv-dev, libcvaux-dev, libhighgui-dev, libboost-graph1.46-dev,
      libksane-dev, libxml2-dev, libxslt-dev, libqt4-opengl-dev, libqjson-dev,
      libgpod-dev and libqca2-dev to build-deps
    + Add packages for kipi-plugins, libmediawiki, libkface, libkgeomap and
      libkvkontakte
  - debian/rules:
    + Don't build with gphoto2 since it doesn't build with it.
  - Add kubuntu_fix_test_linking.diff to fix linking of the dngconverter test
  - update install files
  - update kubuntu_01_mysqld_executable_name.diff for new cmake layout
    and rename to kubuntu_mysqld_executable_name.diff
* Fix typo in digikam-data description (LP: #804894)
* Fix Vcs links

[ Felix Geyer ]
* Move library data files to the new packages libkface-data, libkgeomap-data
  and libkvkontakte-data.
* Override version of the embedded library packages to 1.0~digikam<version>.
* Exclude the library packages from digikam-dbg to prevent file conflicts in
  the future.
* Call dh_install with --list-missing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ============================================================
 
2
 *
 
3
 * This file is a part of kipi-plugins project
 
4
 * http://www.kipi-plugins.org
 
5
 *
 
6
 * Date        : 2007-16-07
 
7
 * Description : a kipi plugin to export images to Picasa web service
 
8
 *
 
9
 * Copyright (C) 2007-2008 by Vardhman Jain <vardhman at gmail dot com>
 
10
 * Copyright (C) 2008-2010 by Gilles Caulier <caulier dot gilles at gmail dot com>
 
11
 * Copyright (C) 2009 by Luka Renko <lure at kubuntu dot org>
 
12
 *
 
13
 * This program is free software; you can redistribute it
 
14
 * and/or modify it under the terms of the GNU General
 
15
 * Public License as published by the Free Software Foundation;
 
16
 * either version 2, or (at your option) any later version.
 
17
 *
 
18
 * This program is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
21
 * GNU General Public License for more details.
 
22
 *
 
23
 * ============================================================ */
 
24
 
 
25
#include "picasawebtalker.moc"
 
26
 
 
27
// C++ includes
 
28
 
 
29
#include <cstring>
 
30
#include <cstdio>
 
31
#include <cstdlib>
 
32
#include <string>
 
33
 
 
34
// Qt includes
 
35
 
 
36
#include <QTextDocument>
 
37
#include <QByteArray>
 
38
#include <QDomDocument>
 
39
#include <QDomElement>
 
40
#include <QDomNode>
 
41
#include <QFile>
 
42
#include <QFileInfo>
 
43
#include <QImage>
 
44
#include <QLinkedList>
 
45
#include <QStringList>
 
46
#include <QUrl>
 
47
#include <QPointer>
 
48
 
 
49
// KDE includes
 
50
 
 
51
#include <kapplication.h>
 
52
#include <kcodecs.h>
 
53
#include <kdebug.h>
 
54
#include <kio/job.h>
 
55
#include <kio/jobclasses.h>
 
56
#include <kio/jobuidelegate.h>
 
57
#include <klineedit.h>
 
58
#include <klocale.h>
 
59
#include <kmessagebox.h>
 
60
#include <kmimetype.h>
 
61
#include <kstandarddirs.h>
 
62
#include <kurl.h>
 
63
 
 
64
// LibKExiv2 includes
 
65
 
 
66
#include <libkexiv2/kexiv2.h>
 
67
 
 
68
// LibKDcraw includes
 
69
 
 
70
#include <libkdcraw/version.h>
 
71
#include <libkdcraw/kdcraw.h>
 
72
 
 
73
// Local includes
 
74
 
 
75
#include "mpform.h"
 
76
#include "picasawebitem.h"
 
77
#include "picasaweblogin.h"
 
78
#include "picasawebwindow.h"
 
79
#include "pluginsversion.h"
 
80
 
 
81
class PicasawebLogin;
 
82
 
 
83
namespace KIPIPicasawebExportPlugin
 
84
{
 
85
 
 
86
PicasawebTalker::PicasawebTalker( QWidget* parent )
 
87
               : m_parent( parent ),  m_job( 0 )
 
88
    {
 
89
        connect(this, SIGNAL(signalError(QString)),
 
90
                this, SLOT(slotError(QString)));
 
91
    }
 
92
 
 
93
PicasawebTalker::~PicasawebTalker()
 
94
{
 
95
    if (m_job)
 
96
        m_job->kill();
 
97
}
 
98
 
 
99
void PicasawebTalker::getToken(const QString& username, const QString& password )
 
100
{
 
101
    if (m_job)
 
102
    {
 
103
        m_job->kill();
 
104
        m_job = 0;
 
105
    }
 
106
 
 
107
    QString url = "https://www.google.com/accounts/ClientLogin";
 
108
 
 
109
    QPointer<PicasawebLogin> loginDialog = new PicasawebLogin(kapp->activeWindow(), i18n("Login"), username, password);
 
110
 
 
111
    QString username_edit, password_edit;
 
112
 
 
113
    if (loginDialog->exec() == QDialog::Accepted)
 
114
    {
 
115
        username_edit = loginDialog->username();
 
116
        password_edit = loginDialog->password();
 
117
        delete loginDialog;
 
118
    }
 
119
    else
 
120
    {
 
121
        delete loginDialog;
 
122
        //Return something which say authentication needed.
 
123
        return ;
 
124
    }
 
125
 
 
126
    m_username    = username_edit;
 
127
    QString accountType = "GOOGLE";
 
128
 
 
129
    QStringList qsl;
 
130
    // do not encode username to support email adress
 
131
    qsl.append("Email="+username_edit);
 
132
    qsl.append("Passwd="+QUrl::toPercentEncoding(password_edit));
 
133
    qsl.append("accountType="+accountType);
 
134
    qsl.append("service=lh2");
 
135
    qsl.append("source=kipi-picasaweb-client");
 
136
    QString dataParameters = qsl.join("&");
 
137
    QByteArray buffer;
 
138
    buffer.append(dataParameters.toUtf8());
 
139
    KIO::TransferJob* job = KIO::http_post(url, buffer, KIO::HideProgressInfo);
 
140
    job->ui()->setWindow(m_parent);
 
141
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" );
 
142
    m_state = FE_GETTOKEN;
 
143
    emit signalLoginProgress(1, 2, "Getting the token");
 
144
 
 
145
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
146
            this, SLOT(data(KIO::Job*,QByteArray)));
 
147
 
 
148
    connect(job, SIGNAL(result(KJob*)),
 
149
            this, SLOT(slotResult(KJob*)));
 
150
 
 
151
    m_job = job;
 
152
    m_buffer.resize(0);
 
153
    emit signalBusy( true );
 
154
}
 
155
 
 
156
void PicasawebTalker::authenticate(const QString& token, const QString& username, const QString& password)
 
157
{
 
158
    if (!token.isNull() || token.length() > 0)
 
159
    {
 
160
        kDebug() << " Checktoken being called" << token ;
 
161
        m_username = username;
 
162
        m_password = password; //this would be needed if the checktoken failed
 
163
                                //we would need to reauthenticate using auth
 
164
        m_token = token;
 
165
        checkToken(token);
 
166
    }
 
167
    else
 
168
    {
 
169
        getToken(username, password);
 
170
    }
 
171
}
 
172
 
 
173
void PicasawebTalker::checkToken(const QString& token)
 
174
{
 
175
    if (m_job)
 
176
    {
 
177
        m_job->kill();
 
178
        m_job = 0;
 
179
    }
 
180
 
 
181
    KUrl url("http://picasaweb.google.com/data/feed/api");
 
182
    url.addPath("/user/" + m_username);
 
183
    kDebug() << " token value is " << token ;
 
184
    QString auth_string = "GoogleLogin auth=" + token;
 
185
    KIO::TransferJob* job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo);
 
186
    job->ui()->setWindow(m_parent);
 
187
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" );
 
188
    job->addMetaData("customHTTPHeader", "Authorization: " + auth_string );
 
189
 
 
190
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
191
            this, SLOT(data(KIO::Job*,QByteArray)));
 
192
 
 
193
    connect(job, SIGNAL(result(KJob*)),
 
194
            this, SLOT(slotResult(KJob*)));
 
195
 
 
196
    m_state = FE_CHECKTOKEN;
 
197
    emit signalLoginProgress(1, 2, "Checking if previous token is still valid");
 
198
    m_job   = job;
 
199
    m_buffer.resize(0);
 
200
    emit signalBusy( true );
 
201
}
 
202
 
 
203
/** PicasaWeb's Album listing request/response
 
204
  * First a request is sent to the url below and then we might(?) get a redirect URL
 
205
  * WE then need to send the GET request to the Redirect url (this however gets taken care off by the
 
206
  * KIO libraries.
 
207
  * This uses the authenticated album list fetching to get all the albums included the unlisted-albums
 
208
  * which is not returned for an unauthorised request as done without the Authorization header.
 
209
*/
 
210
void PicasawebTalker::listAlbums(const QString& username)
 
211
{
 
212
    if (m_job)
 
213
    {
 
214
        m_job->kill();
 
215
        m_job = 0;
 
216
    }
 
217
    KUrl url("http://picasaweb.google.com/data/feed/api");
 
218
    // do not encode username to support email adress
 
219
    url.addPath("/user/" + username);
 
220
    KIO::TransferJob* job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo);
 
221
    job->ui()->setWindow(m_parent);
 
222
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" );
 
223
    if (!m_token.isEmpty())
 
224
    {
 
225
        QString auth_string = "GoogleLogin auth=" + m_token;
 
226
        job->addMetaData("customHTTPHeader", "Authorization: " + auth_string );
 
227
    }
 
228
 
 
229
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
230
            this, SLOT(data(KIO::Job*,QByteArray)));
 
231
 
 
232
    connect(job, SIGNAL(result(KJob*)),
 
233
            this, SLOT(slotResult(KJob*)));
 
234
 
 
235
    m_state = FE_LISTALBUMS;
 
236
    m_job   = job;
 
237
    m_buffer.resize(0);
 
238
    emit signalBusy( true );
 
239
}
 
240
 
 
241
void PicasawebTalker::listPhotos(const QString& username,
 
242
                                 const QString& albumId)
 
243
{
 
244
    if (m_job)
 
245
    {
 
246
        m_job->kill();
 
247
        m_job = 0;
 
248
    }
 
249
    KUrl url("http://picasaweb.google.com/data/feed/api");
 
250
    url.addPath("/user/" + username);
 
251
    url.addPath("/albumid/" + albumId);
 
252
    url.addQueryItem("thumbsize", "200");
 
253
    KIO::TransferJob* job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo);
 
254
    job->ui()->setWindow(m_parent);
 
255
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" );
 
256
    if (!m_token.isEmpty())
 
257
    {
 
258
        QString auth_string = "GoogleLogin auth=" + m_token;
 
259
        job->addMetaData("customHTTPHeader", "Authorization: " + auth_string );
 
260
    }
 
261
 
 
262
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
263
            this, SLOT(data(KIO::Job*,QByteArray)));
 
264
 
 
265
    connect(job, SIGNAL(result(KJob*)),
 
266
            this, SLOT(slotResult(KJob*)));
 
267
 
 
268
    m_state = FE_LISTPHOTOS;
 
269
    m_job   = job;
 
270
    m_buffer.resize(0);
 
271
    emit signalBusy( true );
 
272
}
 
273
 
 
274
void PicasawebTalker::createAlbum(const PicasaWebAlbum& album)
 
275
{
 
276
    if (m_job)
 
277
    {
 
278
        m_job->kill();
 
279
        m_job = 0;
 
280
    }
 
281
 
 
282
    //Create the Body in atom-xml
 
283
    QDomDocument docMeta;
 
284
    QDomProcessingInstruction instr = docMeta.createProcessingInstruction(
 
285
                      "xml", "version='1.0' encoding='UTF-8'");
 
286
    docMeta.appendChild(instr);
 
287
    QDomElement entryElem = docMeta.createElement("entry");
 
288
    docMeta.appendChild(entryElem);
 
289
    entryElem.setAttribute("xmlns", "http://www.w3.org/2005/Atom");
 
290
    QDomElement titleElem = docMeta.createElement("title");
 
291
    entryElem.appendChild(titleElem);
 
292
    QDomText titleText = docMeta.createTextNode(album.title);
 
293
    titleElem.appendChild(titleText);
 
294
    QDomElement summaryElem = docMeta.createElement("summary");
 
295
    entryElem.appendChild(summaryElem);
 
296
    QDomText summaryText = docMeta.createTextNode(album.description);
 
297
    summaryElem.appendChild(summaryText);
 
298
    QDomElement locationElem = docMeta.createElementNS("http://schemas.google.com/photos/2007", "gphoto:location");
 
299
    entryElem.appendChild(locationElem);
 
300
    QDomText locationText = docMeta.createTextNode(album.location);
 
301
    locationElem.appendChild(locationText);
 
302
    QDomElement accessElem = docMeta.createElementNS("http://schemas.google.com/photos/2007", "gphoto:access");
 
303
    entryElem.appendChild(accessElem);
 
304
    QDomText accessText = docMeta.createTextNode(album.access);
 
305
    accessElem.appendChild(accessText);
 
306
    QDomElement commentElem = docMeta.createElementNS("http://schemas.google.com/photos/2007", "gphoto:commentingEnabled");
 
307
    entryElem.appendChild(commentElem);
 
308
    QDomText commentText = docMeta.createTextNode(album.canComment ? "true" : "false");
 
309
    commentElem.appendChild(commentText);
 
310
    QDomElement timestampElem = docMeta.createElementNS("http://schemas.google.com/photos/2007", "gphoto:timestamp");
 
311
    entryElem.appendChild(timestampElem);
 
312
    QDomText timestampText = docMeta.createTextNode(album.timestamp);
 
313
    timestampElem.appendChild(timestampText);
 
314
    QDomElement categoryElem = docMeta.createElement("category");
 
315
    entryElem.appendChild(categoryElem);
 
316
    categoryElem.setAttribute("scheme", "http://schemas.google.com/g/2005#kind");
 
317
    categoryElem.setAttribute("term", "http://schemas.google.com/photos/2007#album");
 
318
    QDomElement mediaGroupElem = docMeta.createElementNS("http://search.yahoo.com/mrss/", "media:group");
 
319
    entryElem.appendChild(mediaGroupElem);
 
320
    QDomElement mediaKeywordsElem = docMeta.createElementNS("http://search.yahoo.com/mrss/", "media:keywords");
 
321
    mediaGroupElem.appendChild(mediaKeywordsElem);
 
322
    QDomText mediaKeywordsText = docMeta.createTextNode(album.tags.join(","));
 
323
    mediaKeywordsElem.appendChild(mediaKeywordsText);
 
324
 
 
325
    QByteArray buffer;
 
326
    buffer.append(docMeta.toString().toUtf8());
 
327
 
 
328
    KUrl url("http://picasaweb.google.com/data/feed/api");
 
329
    url.addPath("/user/" + m_username);
 
330
    QString auth_string = "GoogleLogin auth=" + m_token;
 
331
    KIO::TransferJob* job = KIO::http_post(url, buffer, KIO::HideProgressInfo);
 
332
    job->ui()->setWindow(m_parent);
 
333
    job->addMetaData("content-type", "Content-Type: application/atom+xml");
 
334
    job->addMetaData("content-length", QString("Content-Length: %1").arg(buffer.length()));
 
335
    job->addMetaData("customHTTPHeader", "Authorization: " + auth_string ); 
 
336
 
 
337
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
338
            this, SLOT(data(KIO::Job*,QByteArray)));
 
339
 
 
340
    connect(job, SIGNAL(result(KJob*)),
 
341
            this, SLOT(slotResult(KJob*)));
 
342
 
 
343
    m_state = FE_CREATEALBUM;
 
344
    m_job   = job;
 
345
    m_buffer.resize(0);
 
346
    emit signalBusy(true);
 
347
}
 
348
 
 
349
bool PicasawebTalker::addPhoto(const QString& photoPath, PicasaWebPhoto& info,
 
350
                               const QString& albumId)
 
351
{
 
352
    if (m_job)
 
353
    {
 
354
        m_job->kill();
 
355
        m_job = 0;
 
356
    }
 
357
 
 
358
    KUrl url("http://picasaweb.google.com/data/feed/api");
 
359
    url.addPath("/user/" + m_username);
 
360
    url.addPath("/albumid/" + albumId);
 
361
    QString     auth_string = "GoogleLogin auth=" + m_token;
 
362
    MPForm      form;
 
363
 
 
364
    //Create the Body in atom-xml
 
365
    QDomDocument docMeta;
 
366
    QDomProcessingInstruction instr = docMeta.createProcessingInstruction(
 
367
                      "xml", "version='1.0' encoding='UTF-8'");
 
368
    docMeta.appendChild(instr);
 
369
    QDomElement entryElem = docMeta.createElement("entry");
 
370
    docMeta.appendChild(entryElem);
 
371
    entryElem.setAttribute("xmlns", "http://www.w3.org/2005/Atom");
 
372
    QDomElement titleElem = docMeta.createElement("title");
 
373
    entryElem.appendChild(titleElem);
 
374
    QDomText titleText = docMeta.createTextNode(info.title);
 
375
    titleElem.appendChild(titleText);
 
376
    QDomElement summaryElem = docMeta.createElement("summary");
 
377
    entryElem.appendChild(summaryElem);
 
378
    QDomText summaryText = docMeta.createTextNode(info.description);
 
379
    summaryElem.appendChild(summaryText);
 
380
    QDomElement categoryElem = docMeta.createElement("category");
 
381
    entryElem.appendChild(categoryElem);
 
382
    categoryElem.setAttribute("scheme", "http://schemas.google.com/g/2005#kind");
 
383
    categoryElem.setAttribute("term", "http://schemas.google.com/photos/2007#photo");
 
384
    QDomElement mediaGroupElem = docMeta.createElementNS("http://search.yahoo.com/mrss/", "media:group");
 
385
    entryElem.appendChild(mediaGroupElem);
 
386
    QDomElement mediaKeywordsElem = docMeta.createElementNS("http://search.yahoo.com/mrss/", "media:keywords");
 
387
    mediaGroupElem.appendChild(mediaKeywordsElem);
 
388
    QDomText mediaKeywordsText = docMeta.createTextNode(info.tags.join(","));
 
389
    mediaKeywordsElem.appendChild(mediaKeywordsText);
 
390
    if (!info.gpsLat.isEmpty() && !info.gpsLon.isEmpty())
 
391
    {
 
392
        QDomElement whereElem = docMeta.createElementNS("http://www.georss.org/georss", "georss:where");
 
393
        entryElem.appendChild(whereElem);
 
394
        QDomElement pointElem = docMeta.createElementNS("http://www.opengis.net/gml", "gml:Point");
 
395
        whereElem.appendChild(pointElem);
 
396
        QDomElement gpsElem = docMeta.createElementNS("http://www.opengis.net/gml", "gml:pos");
 
397
        pointElem.appendChild(gpsElem);
 
398
        QDomText gpsVal = docMeta.createTextNode(info.gpsLat + " " + info.gpsLon);
 
399
        gpsElem.appendChild(gpsVal);
 
400
    }
 
401
 
 
402
    form.addPair("descr", docMeta.toString(), "application/atom+xml");
 
403
 
 
404
    if (!form.addFile("photo", photoPath))
 
405
        return false;
 
406
 
 
407
    form.finish();
 
408
 
 
409
    KIO::TransferJob* job = KIO::http_post(url, form.formData(), KIO::HideProgressInfo);
 
410
    job->ui()->setWindow(m_parent);
 
411
    job->addMetaData("content-type", form.contentType());
 
412
    job->addMetaData("content-length", QString("Content-Length: %1").arg(form.formData().length()));
 
413
    job->addMetaData("customHTTPHeader", "Authorization: " + auth_string + "\nMIME-version: 1.0" );
 
414
 
 
415
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
416
            this, SLOT(data(KIO::Job*,QByteArray)));
 
417
 
 
418
    connect(job, SIGNAL(result(KJob*)),
 
419
            this, SLOT(slotResult(KJob*)));
 
420
 
 
421
    m_state = FE_ADDPHOTO;
 
422
    m_job   = job;
 
423
    m_buffer.resize(0);
 
424
    emit signalBusy(true);
 
425
    return true;
 
426
}
 
427
 
 
428
bool PicasawebTalker::updatePhoto(const QString& photoPath, PicasaWebPhoto& info)
 
429
{
 
430
    if (m_job)
 
431
    {
 
432
        m_job->kill();
 
433
        m_job = 0;
 
434
    }
 
435
 
 
436
    MPForm      form;
 
437
 
 
438
    //Create the Body in atom-xml
 
439
    QDomDocument docMeta;
 
440
    QDomProcessingInstruction instr = docMeta.createProcessingInstruction(
 
441
                      "xml", "version='1.0' encoding='UTF-8'");
 
442
    docMeta.appendChild(instr);
 
443
    QDomElement entryElem = docMeta.createElement("entry");
 
444
    docMeta.appendChild(entryElem);
 
445
    entryElem.setAttribute("xmlns", "http://www.w3.org/2005/Atom");
 
446
    QDomElement titleElem = docMeta.createElement("title");
 
447
    entryElem.appendChild(titleElem);
 
448
    QDomText titleText = docMeta.createTextNode(info.title);
 
449
    titleElem.appendChild(titleText);
 
450
    QDomElement summaryElem = docMeta.createElement("summary");
 
451
    entryElem.appendChild(summaryElem);
 
452
    QDomText summaryText = docMeta.createTextNode(info.description);
 
453
    summaryElem.appendChild(summaryText);
 
454
    QDomElement categoryElem = docMeta.createElement("category");
 
455
    entryElem.appendChild(categoryElem);
 
456
    categoryElem.setAttribute("scheme", "http://schemas.google.com/g/2005#kind");
 
457
    categoryElem.setAttribute("term", "http://schemas.google.com/photos/2007#photo");
 
458
    QDomElement mediaGroupElem = docMeta.createElementNS("http://search.yahoo.com/mrss/", "media:group");
 
459
    entryElem.appendChild(mediaGroupElem);
 
460
    QDomElement mediaKeywordsElem = docMeta.createElementNS("http://search.yahoo.com/mrss/", "media:keywords");
 
461
    mediaGroupElem.appendChild(mediaKeywordsElem);
 
462
    QDomText mediaKeywordsText = docMeta.createTextNode(info.tags.join(","));
 
463
    mediaKeywordsElem.appendChild(mediaKeywordsText);
 
464
    if (!info.gpsLat.isEmpty() && !info.gpsLon.isEmpty())
 
465
    {
 
466
        QDomElement whereElem = docMeta.createElementNS("http://www.georss.org/georss", "georss:where");
 
467
        entryElem.appendChild(whereElem);
 
468
        QDomElement pointElem = docMeta.createElementNS("http://www.opengis.net/gml", "gml:Point");
 
469
        whereElem.appendChild(pointElem);
 
470
        QDomElement gpsElem = docMeta.createElementNS("http://www.opengis.net/gml", "gml:pos");
 
471
        pointElem.appendChild(gpsElem);
 
472
        QDomText gpsVal = docMeta.createTextNode(info.gpsLat + " " + info.gpsLon);
 
473
        gpsElem.appendChild(gpsVal);
 
474
    }
 
475
 
 
476
    form.addPair("descr", docMeta.toString(), "application/atom+xml");
 
477
 
 
478
    if (!form.addFile("photo", photoPath))
 
479
        return false;
 
480
 
 
481
    form.finish();
 
482
 
 
483
    QString auth_string = "GoogleLogin auth=" + m_token;
 
484
    KIO::TransferJob* job = KIO::put(info.editUrl, -1, KIO::HideProgressInfo);
 
485
    job->ui()->setWindow(m_parent);
 
486
    job->addMetaData("content-type", form.contentType());
 
487
    job->addMetaData("content-length", QString("Content-Length: %1").arg(form.formData().length()));
 
488
    job->addMetaData("customHTTPHeader", "Authorization: " + auth_string + "\nIf-Match: *");
 
489
 
 
490
    m_jobData.insert(job, form.formData());
 
491
 
 
492
    connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
 
493
            this, SLOT(dataReq(KIO::Job*,QByteArray&)));
 
494
 
 
495
    connect(job, SIGNAL(result(KJob*)),
 
496
            this, SLOT(slotResult(KJob*)));
 
497
 
 
498
    m_state = FE_UPDATEPHOTO;
 
499
    m_job   = job;
 
500
    m_buffer.resize(0);
 
501
    emit signalBusy(true);
 
502
    return true;
 
503
}
 
504
 
 
505
void PicasawebTalker::getPhoto(const QString& imgPath)
 
506
{
 
507
    if (m_job)
 
508
    {
 
509
        m_job->kill();
 
510
        m_job = 0;
 
511
    }
 
512
    emit signalBusy(true);
 
513
 
 
514
    KIO::TransferJob* job = KIO::get(imgPath, KIO::Reload, KIO::HideProgressInfo);
 
515
    //job->addMetaData("customHTTPHeader", "Authorization: " + auth_string );
 
516
 
 
517
    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
 
518
            this, SLOT(data(KIO::Job*,QByteArray)));
 
519
 
 
520
    connect(job, SIGNAL(result(KJob*)),
 
521
            this, SLOT(slotResult(KJob*)));
 
522
 
 
523
    m_state = FE_GETPHOTO;
 
524
    m_job   = job;
 
525
    m_buffer.resize(0);
 
526
}
 
527
 
 
528
QString PicasawebTalker::getUserName()
 
529
{
 
530
    return m_username;
 
531
}
 
532
 
 
533
void PicasawebTalker::cancel()
 
534
{
 
535
    if (m_job)
 
536
    {
 
537
        m_job->kill();
 
538
        m_job = 0;
 
539
    }
 
540
 
 
541
    emit signalBusy(false);
 
542
}
 
543
 
 
544
void PicasawebTalker::info(KIO::Job* /*job*/, const QString& /*str*/)
 
545
{
 
546
}
 
547
 
 
548
void PicasawebTalker::data(KIO::Job*, const QByteArray& data)
 
549
{
 
550
    if (data.isEmpty())
 
551
        return;
 
552
 
 
553
    int oldSize = m_buffer.size();
 
554
    m_buffer.resize(m_buffer.size() + data.size());
 
555
    memcpy(m_buffer.data()+oldSize, data.data(), data.size());
 
556
}
 
557
 
 
558
void PicasawebTalker::dataReq(KIO::Job* job, QByteArray& data)
 
559
{
 
560
    if (m_jobData.contains(job))
 
561
    {
 
562
        data = m_jobData.value(job);
 
563
        m_jobData.remove(job);
 
564
    }
 
565
}
 
566
 
 
567
void PicasawebTalker::slotError(const QString & error)
 
568
{
 
569
    QString transError;
 
570
    int     errorNo = 0;
 
571
 
 
572
    if (!error.isEmpty())
 
573
        errorNo = error.toInt();
 
574
 
 
575
    switch (errorNo)
 
576
    {
 
577
        case 2:
 
578
            transError=i18n("No photo specified");break;
 
579
        case 3:
 
580
            transError=i18n("General upload failure");break;
 
581
        case 4:
 
582
            transError=i18n("File-size was zero");break;
 
583
        case 5:
 
584
            transError=i18n("File-type was not recognized");break;
 
585
        case 6:
 
586
            transError=i18n("User exceeded upload limit");break;
 
587
        case 96:
 
588
            transError=i18n("Invalid signature"); break;
 
589
        case 97:
 
590
            transError=i18n("Missing signature"); break;
 
591
        case 98:
 
592
            transError=i18n("Login failed / Invalid auth token"); break;
 
593
        case 100:
 
594
            transError=i18n("Invalid API Key"); break;
 
595
        case 105:
 
596
            transError=i18n("Service currently unavailable");break;
 
597
        case 108:
 
598
            transError=i18n("Invalid Frob");break;
 
599
        case 111:
 
600
            transError=i18n("Format \"xxx\" not found"); break;
 
601
        case 112:
 
602
            transError=i18n("Method \"xxx\" not found"); break;
 
603
        case 114:
 
604
            transError=i18n("Invalid SOAP envelope");break;
 
605
        case 115:
 
606
            transError=i18n("Invalid XML-RPC Method Call");break;
 
607
        case 116:
 
608
            transError=i18n("The POST method is now required for all setters."); break;
 
609
        default:
 
610
            transError=i18n("Unknown error");
 
611
    };
 
612
 
 
613
    KMessageBox::error(kapp->activeWindow(), i18n("Error occurred: %1\nUnable to proceed further.",transError + error));
 
614
}
 
615
 
 
616
void PicasawebTalker::slotResult(KJob *job)
 
617
{
 
618
    m_job = 0;
 
619
    emit signalBusy(false);
 
620
 
 
621
    if (job->error())
 
622
    {
 
623
        if (m_state == FE_ADDPHOTO)
 
624
        {
 
625
            emit signalAddPhotoDone(job->error(), job->errorText(), "");
 
626
        }
 
627
        else
 
628
        {
 
629
            static_cast<KIO::Job*>(job)->ui()->showErrorMessage();
 
630
        }
 
631
 
 
632
        return;
 
633
    }
 
634
    if (static_cast<KIO::TransferJob*>(job)->isErrorPage())
 
635
    {
 
636
        if (m_state == FE_CHECKTOKEN) 
 
637
        {
 
638
            kDebug() << " Error encountered in checking token, require user credentials" ;
 
639
            return getToken(m_username, "");
 
640
        }
 
641
    }
 
642
    switch(m_state)
 
643
    {
 
644
        case(FE_LOGIN):
 
645
            //parseResponseLogin(m_buffer);
 
646
            break;
 
647
        case(FE_CREATEALBUM):
 
648
            parseResponseCreateAlbum(m_buffer);
 
649
            break;
 
650
        case(FE_LISTALBUMS):
 
651
            parseResponseListAlbums(m_buffer);
 
652
            break;
 
653
        case(FE_GETTOKEN):
 
654
            parseResponseGetToken(m_buffer);
 
655
            break;
 
656
        case(FE_CHECKTOKEN):
 
657
            parseResponseCheckToken(m_buffer);
 
658
            break;
 
659
        case(FE_LISTPHOTOS):
 
660
            parseResponseListPhotos(m_buffer);
 
661
            break;
 
662
        case(FE_ADDPHOTO):
 
663
            parseResponseAddPhoto(m_buffer);
 
664
            break;
 
665
        case(FE_UPDATEPHOTO):
 
666
            emit signalAddPhotoDone(0, "", "");
 
667
            break;
 
668
        case(FE_GETPHOTO):
 
669
            // all we get is data of the image
 
670
            emit signalGetPhotoDone(0, QString(), m_buffer);
 
671
            break;
 
672
    }
 
673
}
 
674
 
 
675
void PicasawebTalker::parseResponseCheckToken(const QByteArray& /*data*/)
 
676
{
 
677
    bool success = true;
 
678
    // TODO(vardhman): Fix this with proper error handling.
 
679
    if(!success)
 
680
        getToken(m_username, m_password);
 
681
    emit signalLoginDone(0, "");
 
682
}
 
683
 
 
684
void PicasawebTalker::parseResponseGetToken(const QByteArray& data)
 
685
{
 
686
    bool success = false;
 
687
    QString errorString;
 
688
    QString str(data);
 
689
    //Check the response code should it be 200, proceed
 
690
    //if it is 403 handle the error mesg
 
691
    //figure out the auth string from this response
 
692
 
 
693
    if (str.contains("Auth="))
 
694
    {
 
695
        QStringList strList = str.split("Auth=");
 
696
        if ( strList.count() > 0 )
 
697
        {
 
698
            m_token = strList[1].trimmed();
 
699
            kDebug() << " m_token as obtained in token Response " << m_token ;
 
700
            success = true;
 
701
        }
 
702
    }
 
703
 
 
704
    if(success)
 
705
    {
 
706
        emit signalLoginDone(0, "");
 
707
    }
 
708
    else
 
709
    {
 
710
        emit signalError("98");
 
711
    }
 
712
}
 
713
 
 
714
void PicasawebTalker::parseResponseListAlbums(const QByteArray& data)
 
715
{
 
716
    QDomDocument doc( "feed" );
 
717
    if ( !doc.setContent( data ) )
 
718
    {
 
719
        emit signalListAlbumsDone(1, i18n("Failed to fetch photo-set list"), QList<PicasaWebAlbum>());
 
720
        return;
 
721
    }
 
722
 
 
723
    QDomElement docElem = doc.documentElement();
 
724
    QDomNode node = docElem.firstChild();
 
725
    QDomElement e;
 
726
 
 
727
    QList<PicasaWebAlbum> albumList;
 
728
 
 
729
    while(!node.isNull())
 
730
    {
 
731
        if(node.isElement() && node.nodeName() == "gphoto:user")
 
732
        {
 
733
            m_username = node.toElement().text();
 
734
        }
 
735
 
 
736
        if (node.isElement() && node.nodeName() == "entry")
 
737
        {
 
738
            e = node.toElement();
 
739
            QDomNode details=e.firstChild();
 
740
            PicasaWebAlbum fps;
 
741
            QDomNode detailsNode = details;
 
742
 
 
743
            while(!detailsNode.isNull())
 
744
            {
 
745
                if(detailsNode.isElement())
 
746
                {
 
747
                    if(detailsNode.nodeName() == "gphoto:id")
 
748
                    {
 
749
                        fps.id = detailsNode.toElement().text();
 
750
                    }
 
751
 
 
752
                    if(detailsNode.nodeName() == "title")
 
753
                    {
 
754
                        fps.title = detailsNode.toElement().text();
 
755
                    }
 
756
 
 
757
                    if(detailsNode.nodeName()=="gphoto:access")
 
758
                    {
 
759
                        fps.access = detailsNode.toElement().text();
 
760
                    }
 
761
                }
 
762
                detailsNode = detailsNode.nextSibling();
 
763
            }
 
764
            albumList.append(fps);
 
765
        }
 
766
        node = node.nextSibling();
 
767
    }
 
768
 
 
769
    emit signalListAlbumsDone(0, "", albumList);
 
770
}
 
771
 
 
772
void PicasawebTalker::parseResponseListPhotos(const QByteArray& data)
 
773
{
 
774
    QDomDocument doc( "feed" );
 
775
    if ( !doc.setContent( data ) )
 
776
    {
 
777
        emit signalListPhotosDone(1, i18n("Failed to fetch photo-set list"), QList<PicasaWebPhoto>());
 
778
        return;
 
779
    }
 
780
 
 
781
    QDomElement docElem = doc.documentElement();
 
782
    QDomNode node = docElem.firstChild();
 
783
 
 
784
    QList<PicasaWebPhoto> photoList;
 
785
 
 
786
    while(!node.isNull())
 
787
    {
 
788
        if (node.isElement() && node.nodeName() == "entry")
 
789
        {
 
790
            QDomNode details = node.firstChild();
 
791
            PicasaWebPhoto fps;
 
792
            QDomNode detailsNode = details;
 
793
 
 
794
            while(!detailsNode.isNull())
 
795
            {
 
796
                if(detailsNode.isElement())
 
797
                {
 
798
                    QDomElement detailsElem = detailsNode.toElement();
 
799
                    if(detailsNode.nodeName() == "gphoto:id")
 
800
                    {
 
801
                        fps.id = detailsElem.text();
 
802
                    }
 
803
 
 
804
                    if(detailsNode.nodeName() == "title")
 
805
                    {
 
806
                        fps.title = detailsElem.text();
 
807
                    }
 
808
 
 
809
                    if(detailsNode.nodeName()=="gphoto:access")
 
810
                    {
 
811
                        fps.access = detailsElem.text();
 
812
                    }
 
813
 
 
814
                    if (detailsNode.nodeName() == "link" && detailsElem.attribute("rel") == "edit-media")
 
815
                    {
 
816
                        fps.editUrl = detailsElem.attribute("href");
 
817
                    }
 
818
 
 
819
                    if(detailsNode.nodeName()=="georss:where")
 
820
                    {
 
821
                        QDomNode geoPointNode = detailsElem.namedItem("gml:Point");
 
822
                        if (!geoPointNode.isNull() && geoPointNode.isElement())
 
823
                        {
 
824
                            QDomNode geoPosNode = geoPointNode.toElement().namedItem("gml:pos");
 
825
                            if (!geoPosNode.isNull() && geoPosNode.isElement())
 
826
                            {
 
827
                                QStringList value = geoPosNode.toElement().text().split(" ");
 
828
                                if (value.size() == 2)
 
829
                                {
 
830
                                    fps.gpsLat = value[0];
 
831
                                    fps.gpsLon = value[1];
 
832
                                }
 
833
                            }
 
834
                        }
 
835
                    }
 
836
 
 
837
                    if(detailsNode.nodeName()=="media:group")
 
838
                    {
 
839
                        QDomNode thumbNode = detailsElem.namedItem("media:thumbnail");
 
840
                        if (!thumbNode.isNull() && thumbNode.isElement())
 
841
                        {
 
842
                            fps.thumbURL = thumbNode.toElement().attribute("url", "");
 
843
                        }
 
844
                        QDomNode keywordNode = detailsElem.namedItem("media:keywords");
 
845
                        if (!keywordNode.isNull() && keywordNode.isElement())
 
846
                        {
 
847
                            fps.tags = keywordNode.toElement().text().split(",");
 
848
                        }
 
849
 
 
850
                        QDomNodeList contentsList = detailsElem.elementsByTagName("media:content");
 
851
                        for(int i = 0; i < contentsList.size(); ++i)
 
852
                        {
 
853
                            QDomElement contentElem = contentsList.at(i).toElement();
 
854
                            if (!contentElem.isNull())
 
855
                            {
 
856
                                if ((contentElem.attribute("medium") == "image") &&
 
857
                                    fps.originalURL.isEmpty())
 
858
                                {
 
859
                                    fps.originalURL = contentElem.attribute("url");
 
860
                                    fps.mimeType = contentElem.attribute("type");
 
861
                                }
 
862
 
 
863
                                if ((contentElem.attribute("medium") == "video") &&
 
864
                                    (contentElem.attribute("type") == "video/mpeg4"))
 
865
                                {
 
866
                                    fps.originalURL = contentElem.attribute("url");
 
867
                                    fps.mimeType = contentElem.attribute("type");
 
868
                                }
 
869
                            }
 
870
                        }
 
871
                    }
 
872
                }
 
873
                detailsNode = detailsNode.nextSibling();
 
874
            }
 
875
            photoList.append(fps);
 
876
        }
 
877
        node = node.nextSibling();
 
878
    }
 
879
 
 
880
    emit signalListPhotosDone(0, "", photoList);
 
881
}
 
882
 
 
883
void PicasawebTalker::parseResponseCreateAlbum(const QByteArray& data)
 
884
{
 
885
    bool success = false;
 
886
 
 
887
    QDomDocument doc( "AddPhoto Response" );
 
888
    if ( !doc.setContent( data ) )
 
889
    {
 
890
        signalCreateAlbumDone(1, i18n("Failed to create album"), "-1");
 
891
        return;
 
892
    }
 
893
 
 
894
    // parse the new album name
 
895
    QDomElement docElem = doc.documentElement();
 
896
    QString albumId("");
 
897
    if (docElem.nodeName() == "entry")
 
898
    {
 
899
        success = true;
 
900
        QDomNode node = docElem.firstChild(); //this should mean <entry>
 
901
        while( !node.isNull() )
 
902
        {
 
903
            if ( node.isElement())
 
904
            {
 
905
                if (node.nodeName() == "gphoto:id")
 
906
                {
 
907
                    albumId = node.toElement().text();
 
908
                }
 
909
             }
 
910
            node = node.nextSibling();
 
911
        }
 
912
    }
 
913
 
 
914
    if(success == true)
 
915
    {
 
916
        signalCreateAlbumDone(0, "", albumId);
 
917
    }
 
918
    else
 
919
    {
 
920
        signalCreateAlbumDone(1, i18n("Failed to create album"), "-1");
 
921
    }
 
922
}
 
923
 
 
924
void PicasawebTalker::parseResponseAddPhoto(const QByteArray& data)
 
925
{
 
926
    QDomDocument doc( "AddPhoto Response" );
 
927
    if ( !doc.setContent( data ) )
 
928
    {
 
929
        emit signalAddPhotoDone(1, i18n("Failed to upload photo"), "");
 
930
        return;
 
931
    }
 
932
 
 
933
    // parse the new album name
 
934
    QDomElement docElem = doc.documentElement();
 
935
    QString photoId("");
 
936
    if (docElem.nodeName() == "entry")
 
937
    {
 
938
        QDomNode node = docElem.firstChild(); //this should mean <entry>
 
939
        while(!node.isNull())
 
940
        {
 
941
            if (node.isElement())
 
942
            {
 
943
                if (node.nodeName() == "gphoto:id")
 
944
                {
 
945
                    photoId = node.toElement().text();
 
946
                }
 
947
            }
 
948
            node = node.nextSibling();
 
949
        }
 
950
    }
 
951
 
 
952
    emit signalAddPhotoDone(0, "", photoId);
 
953
}
 
954
 
 
955
} // KIPIPicasawebExportPlugin