You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
682 lines
19 KiB
682 lines
19 KiB
/* ============================================================
|
|
* File : gallerytalker.cpp
|
|
* Author: Renchi Raju <renchi@pooh.tam.uiuc.edu>
|
|
* Date : 2004-11-30
|
|
* Description :
|
|
*
|
|
* Copyright 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
|
|
|
|
* This program is free software; you can redistribute it
|
|
* and/or modify it under the terms of the GNU General
|
|
* Public License as published by the Free Software Foundation;
|
|
* either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* ============================================================ */
|
|
|
|
#include <tqcstring.h>
|
|
#include <tqtextstream.h>
|
|
#include <tqfile.h>
|
|
#include <tqimage.h>
|
|
#include <tqregexp.h>
|
|
|
|
#include <tdelocale.h>
|
|
#include <tdeio/job.h>
|
|
#include <kdebug.h>
|
|
#include <kmimetype.h>
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <cstring>
|
|
#include <cstdio>
|
|
|
|
// LibKExiv2 includes.
|
|
|
|
#include <libkexiv2/kexiv2.h>
|
|
|
|
#include "galleryitem.h"
|
|
#include "gallerympform.h"
|
|
#include "gallerytalker.h"
|
|
|
|
namespace KIPIGalleryExportPlugin
|
|
{
|
|
|
|
GalleryTalker::GalleryTalker( TQWidget* parent )
|
|
: m_parent( parent ), m_job( 0 ), m_loggedIn( false )
|
|
{
|
|
}
|
|
|
|
GalleryTalker::~GalleryTalker()
|
|
{
|
|
if (m_job)
|
|
m_job->kill();
|
|
}
|
|
|
|
bool GalleryTalker::s_using_gallery2 = true;
|
|
TQString GalleryTalker::s_authToken = "";
|
|
|
|
bool GalleryTalker::loggedIn() const
|
|
{
|
|
return m_loggedIn;
|
|
}
|
|
|
|
void GalleryTalker::login( const KURL& url, const TQString& name,
|
|
const TQString& passwd )
|
|
{
|
|
m_url = url;
|
|
|
|
GalleryMPForm form;
|
|
|
|
form.addPair("cmd", "login");
|
|
form.addPair("protocol_version", "2.11");
|
|
form.addPair("uname", name);
|
|
form.addPair("password", passwd);
|
|
form.finish();
|
|
|
|
TDEIO::TransferJob* job = TDEIO::http_post(m_url, form.formData(), false);
|
|
job->addMetaData("content-type", form.contentType() );
|
|
job->addMetaData("cookies", "manual");
|
|
connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
|
|
TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));
|
|
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
|
|
TQ_SLOT(slotResult(TDEIO::Job *)));
|
|
|
|
m_state = GE_LOGIN;
|
|
m_job = job;
|
|
m_buffer.resize(0);
|
|
emit signalBusy( true );
|
|
}
|
|
|
|
void GalleryTalker::listAlbums()
|
|
{
|
|
GalleryMPForm form;
|
|
|
|
TQString task = "fetch-albums";
|
|
if (s_using_gallery2)
|
|
task = "fetch-albums-prune";
|
|
|
|
form.addPair("cmd", task);
|
|
form.addPair("protocol_version", "2.11");
|
|
form.finish();
|
|
|
|
TDEIO::TransferJob* job = TDEIO::http_post(m_url, form.formData(), false);
|
|
job->addMetaData("content-type", form.contentType() );
|
|
job->addMetaData("cookies", "manual");
|
|
job->addMetaData("setcookies", m_cookie);
|
|
connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
|
|
TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));
|
|
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
|
|
TQ_SLOT(slotResult(TDEIO::Job *)));
|
|
|
|
m_state = GE_LISTALBUMS;
|
|
m_job = job;
|
|
m_buffer.resize(0);
|
|
emit signalBusy( true );
|
|
}
|
|
|
|
void GalleryTalker::listPhotos( const TQString& albumName )
|
|
{
|
|
if (m_job)
|
|
{
|
|
m_job->kill();
|
|
m_job = 0;
|
|
}
|
|
|
|
GalleryMPForm form;
|
|
|
|
form.addPair("cmd", "fetch-album-images");
|
|
form.addPair("protocol_version", "2.11");
|
|
form.addPair("set_albumName", albumName);
|
|
form.finish();
|
|
|
|
TDEIO::TransferJob* job = TDEIO::http_post(m_url, form.formData(), false);
|
|
job->addMetaData("content-type", form.contentType() );
|
|
job->addMetaData("cookies", "manual");
|
|
job->addMetaData("setcookies", m_cookie);
|
|
connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
|
|
TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));
|
|
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
|
|
TQ_SLOT(slotResult(TDEIO::Job *)));
|
|
|
|
m_state = GE_LISTPHOTOS;
|
|
m_job = job;
|
|
m_buffer.resize(0);
|
|
emit signalBusy( true );
|
|
}
|
|
|
|
void GalleryTalker::createAlbum( const TQString& parentAlbumName,
|
|
const TQString& albumName,
|
|
const TQString& albumTitle,
|
|
const TQString& albumCaption )
|
|
{
|
|
if (m_job)
|
|
{
|
|
m_job->kill();
|
|
m_job = 0;
|
|
}
|
|
|
|
GalleryMPForm form;
|
|
|
|
form.addPair("cmd", "new-album");
|
|
form.addPair("protocol_version", "2.11");
|
|
form.addPair("set_albumName", parentAlbumName);
|
|
if (!albumName.isEmpty())
|
|
form.addPair("newAlbumName", albumName);
|
|
if (!albumTitle.isEmpty())
|
|
form.addPair("newAlbumTitle", albumTitle);
|
|
if (!albumCaption.isEmpty())
|
|
form.addPair("newAlbumDesc", albumCaption);
|
|
form.finish();
|
|
|
|
TDEIO::TransferJob* job = TDEIO::http_post(m_url, form.formData(), false);
|
|
job->addMetaData("content-type", form.contentType() );
|
|
job->addMetaData("cookies", "manual");
|
|
job->addMetaData("setcookies", m_cookie);
|
|
connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
|
|
TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));
|
|
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
|
|
TQ_SLOT(slotResult(TDEIO::Job *)));
|
|
|
|
m_state = GE_CREATEALBUM;
|
|
m_job = job;
|
|
m_buffer.resize(0);
|
|
emit signalBusy( true );
|
|
}
|
|
|
|
bool GalleryTalker::addPhoto( const TQString& albumName,
|
|
const TQString& photoPath,
|
|
const TQString& caption,
|
|
bool captionIsTitle, bool captionIsDescription,
|
|
bool rescale, int maxDim )
|
|
{
|
|
if (m_job)
|
|
{
|
|
m_job->kill();
|
|
m_job = 0;
|
|
}
|
|
|
|
TQString path = photoPath;
|
|
TQString display_filename = TQFile::encodeName(KURL(path).filename());
|
|
|
|
GalleryMPForm form;
|
|
|
|
form.addPair("cmd", "add-item");
|
|
form.addPair("protocol_version", "2.11");
|
|
form.addPair("set_albumName", albumName);
|
|
|
|
if (!caption.isEmpty())
|
|
{
|
|
if (captionIsTitle)
|
|
form.addPair("caption", caption);
|
|
if (captionIsDescription)
|
|
form.addPair("extrafield.Description", caption);
|
|
}
|
|
TQImage image(photoPath);
|
|
|
|
if (!image.isNull())
|
|
{
|
|
// image file - see if we need to rescale it
|
|
if (rescale && (image.width() > maxDim || image.height() > maxDim))
|
|
{
|
|
image = image.smoothScale(maxDim, maxDim, TQImage::ScaleMin);
|
|
path = locateLocal("tmp", KURL(photoPath).filename());
|
|
image.save(path, TQImageIO::imageFormat(photoPath));
|
|
|
|
if ("JPEG" == TQString(TQImageIO::imageFormat(photoPath)).upper())
|
|
{
|
|
KExiv2Iface::KExiv2 exiv2;
|
|
if (exiv2.load(photoPath))
|
|
{
|
|
exiv2.save(path);
|
|
}
|
|
}
|
|
kdDebug() << "Resizing and saving to temp file: "
|
|
<< path << endl;
|
|
}
|
|
}
|
|
|
|
// The filename bit can perhaps be calculated in addFile()
|
|
// but not sure of the temporary filename that could be
|
|
// used for resizing... so I've added it explicitly for now.
|
|
if (!form.addFile(path, display_filename))
|
|
return false;
|
|
|
|
form.finish();
|
|
|
|
TDEIO::TransferJob* job = TDEIO::http_post(m_url, form.formData(), false);
|
|
job->addMetaData("content-type", form.contentType());
|
|
job->addMetaData("cookies", "manual");
|
|
job->addMetaData("setcookies", m_cookie);
|
|
connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
|
|
TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));
|
|
connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
|
|
TQ_SLOT(slotResult(TDEIO::Job *)));
|
|
|
|
m_state = GE_ADDPHOTO;
|
|
m_job = job;
|
|
m_buffer.resize(0);
|
|
emit signalBusy( true );
|
|
|
|
return true;
|
|
}
|
|
|
|
void GalleryTalker::cancel()
|
|
{
|
|
if (m_job)
|
|
{
|
|
m_job->kill();
|
|
m_job = 0;
|
|
}
|
|
}
|
|
|
|
void GalleryTalker::data(TDEIO::Job*, const TQByteArray& data)
|
|
{
|
|
if (data.isEmpty())
|
|
return;
|
|
|
|
int oldSize = m_buffer.size();
|
|
m_buffer.resize(m_buffer.size() + data.size());
|
|
memcpy(m_buffer.data()+oldSize, data.data(), data.size());
|
|
}
|
|
|
|
void GalleryTalker::slotResult(TDEIO::Job *job)
|
|
{
|
|
m_job = 0;
|
|
emit signalBusy( false );
|
|
|
|
if ( job->error() )
|
|
{
|
|
if ( m_state == GE_LOGIN )
|
|
emit signalLoginFailed( job->errorString() );
|
|
else if ( m_state == GE_ADDPHOTO )
|
|
emit signalAddPhotoFailed( job->errorString() );
|
|
else
|
|
job->showErrorDialog( m_parent );
|
|
return;
|
|
}
|
|
|
|
switch(m_state)
|
|
{
|
|
case(GE_LOGIN):
|
|
parseResponseLogin(m_buffer);
|
|
break;
|
|
case(GE_LISTALBUMS):
|
|
parseResponseListAlbums(m_buffer);
|
|
break;
|
|
case(GE_LISTPHOTOS):
|
|
parseResponseListPhotos(m_buffer);
|
|
break;
|
|
case(GE_CREATEALBUM):
|
|
parseResponseCreateAlbum(m_buffer);
|
|
break;
|
|
case(GE_ADDPHOTO):
|
|
parseResponseAddPhoto(m_buffer);
|
|
break;
|
|
}
|
|
|
|
if (m_state == GE_LOGIN && m_loggedIn)
|
|
{
|
|
TQStringList cookielist = TQStringList::split("\n", job->queryMetaData("setcookies"));
|
|
m_cookie = "Cookie:";
|
|
for (TQStringList::Iterator it = cookielist.begin(); it != cookielist.end(); ++it)
|
|
{
|
|
TQRegExp rx("^Set-Cookie: ([^;]+=[^;]+)");
|
|
if (rx.search(*it) > -1)
|
|
m_cookie += " " + rx.cap(1) + ";";
|
|
}
|
|
listAlbums();
|
|
}
|
|
}
|
|
|
|
void GalleryTalker::parseResponseLogin(const TQByteArray &data)
|
|
{
|
|
TQTextStream ts(data, IO_ReadOnly );
|
|
ts.setEncoding(TQTextStream::UnicodeUTF8);
|
|
TQString line;
|
|
bool foundResponse = false;
|
|
|
|
m_loggedIn = false;
|
|
|
|
while (!ts.atEnd())
|
|
{
|
|
line = ts.readLine();
|
|
|
|
if (!foundResponse)
|
|
{
|
|
foundResponse = line.startsWith("#__GR2PROTO__");
|
|
}
|
|
else
|
|
{
|
|
TQStringList strlist = TQStringList::split("=", line);
|
|
if (strlist.count() == 2)
|
|
{
|
|
if (("status" == strlist[0]) && ("0" == strlist[1]))
|
|
{
|
|
m_loggedIn = true;
|
|
}
|
|
else if ("auth_token" == strlist[0])
|
|
{
|
|
s_authToken = strlist[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundResponse)
|
|
{
|
|
emit signalLoginFailed( i18n("Gallery URL probably incorrect"));
|
|
return;
|
|
}
|
|
|
|
if (!m_loggedIn)
|
|
{
|
|
emit signalLoginFailed(i18n("Incorrect username or password specified"));
|
|
}
|
|
}
|
|
|
|
void GalleryTalker::parseResponseListAlbums(const TQByteArray &data)
|
|
{
|
|
TQTextStream ts(data, IO_ReadOnly );
|
|
ts.setEncoding(TQTextStream::UnicodeUTF8);
|
|
TQString line;
|
|
bool foundResponse = false;
|
|
bool success = false;
|
|
|
|
typedef TQValueList<GAlbum> GAlbumList;
|
|
GAlbumList albumList;
|
|
GAlbumList::iterator iter = albumList.begin();
|
|
|
|
while (!ts.atEnd())
|
|
{
|
|
line = ts.readLine();
|
|
if (!foundResponse)
|
|
{
|
|
foundResponse = line.startsWith("#__GR2PROTO__");
|
|
}
|
|
else
|
|
{
|
|
TQStringList strlist = TQStringList::split("=", line);
|
|
if (strlist.count() == 2)
|
|
{
|
|
TQString key = strlist[0];
|
|
TQString value = strlist[1];
|
|
|
|
if (key == "status")
|
|
{
|
|
success = (value == "0");
|
|
}
|
|
else if (key.startsWith("album.name"))
|
|
{
|
|
GAlbum album;
|
|
album.name = value;
|
|
if (s_using_gallery2)
|
|
album.ref_num = value.toInt();
|
|
else
|
|
album.ref_num = key.section(".", 2, 2).toInt();
|
|
iter = albumList.append(album);
|
|
}
|
|
else if (key.startsWith("album.title"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).title = value;
|
|
}
|
|
else if (key.startsWith("album.summary"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).summary = value;
|
|
}
|
|
else if (key.startsWith("album.parent"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).parent_ref_num = value.toInt();
|
|
}
|
|
else if (key.startsWith("album.perms.add"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).add = (value == "true");
|
|
}
|
|
else if (key.startsWith("album.perms.write"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).write = (value == "true");
|
|
}
|
|
else if (key.startsWith("album.perms.del_item"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).del_item = (value == "true");
|
|
}
|
|
else if (key.startsWith("album.perms.del_alb"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).del_alb = (value == "true");
|
|
}
|
|
else if (key.startsWith("album.perms.create_sub"))
|
|
{
|
|
if (iter != albumList.end())
|
|
(*iter).create_sub = (value == "true");
|
|
}
|
|
else if (key == "auth_token")
|
|
{
|
|
s_authToken = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundResponse)
|
|
{
|
|
emit signalError(i18n("Invalid response received from remote Gallery"));
|
|
return;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
emit signalError(i18n("Failed to list albums"));
|
|
return;
|
|
}
|
|
|
|
// We need parent albums to come first for rest of the code to work
|
|
qHeapSort(albumList);
|
|
|
|
emit signalAlbums( albumList );
|
|
}
|
|
|
|
void GalleryTalker::parseResponseListPhotos(const TQByteArray &data)
|
|
{
|
|
TQTextStream ts(data, IO_ReadOnly );
|
|
ts.setEncoding(TQTextStream::UnicodeUTF8);
|
|
TQString line;
|
|
bool foundResponse = false;
|
|
bool success = false;
|
|
|
|
typedef TQValueList<GPhoto> GPhotoList;
|
|
GPhotoList photoList;
|
|
GPhotoList::iterator iter = photoList.begin();
|
|
|
|
TQString albumURL;
|
|
|
|
while (!ts.atEnd())
|
|
{
|
|
line = ts.readLine();
|
|
|
|
if (!foundResponse)
|
|
{
|
|
foundResponse = line.startsWith("#__GR2PROTO__");
|
|
}
|
|
else
|
|
{
|
|
// Boris the Gallery default URL contains "=" char. So we will split the string only from the first "=" char
|
|
TQStringList strlist = TQStringList();
|
|
strlist << line.left(line.find('=')) << line.mid(line.find('=')+1);
|
|
if (strlist.count() >= 2)
|
|
{
|
|
TQString key = strlist[0];
|
|
TQString value = strlist[1];
|
|
|
|
if (key == "status")
|
|
{
|
|
success = (value == "0");
|
|
}
|
|
else if (key.startsWith("image.name"))
|
|
{
|
|
GPhoto photo;
|
|
photo.name = value;
|
|
photo.ref_num = key.section(".", 2, 2).toInt();
|
|
iter = photoList.append(photo);
|
|
}
|
|
else if (key.startsWith("image.caption"))
|
|
{
|
|
if (iter != photoList.end())
|
|
(*iter).caption = value;
|
|
}
|
|
else if (key.startsWith("image.thumbName"))
|
|
{
|
|
if (iter != photoList.end())
|
|
(*iter).thumbName = value;
|
|
}
|
|
else if (key.startsWith("baseurl"))
|
|
{
|
|
albumURL = value.replace("\\","");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundResponse)
|
|
{
|
|
emit signalError(i18n("Invalid response received from remote Gallery"));
|
|
return;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
emit signalError(i18n("Failed to list photos"));
|
|
return;
|
|
}
|
|
|
|
for ( iter = photoList.begin(); iter != photoList.end(); ++iter )
|
|
{
|
|
(*iter).albumURL = albumURL;
|
|
}
|
|
|
|
emit signalPhotos( photoList );
|
|
}
|
|
|
|
void GalleryTalker::parseResponseCreateAlbum(const TQByteArray &data)
|
|
{
|
|
TQTextStream ts(data, IO_ReadOnly );
|
|
ts.setEncoding(TQTextStream::UnicodeUTF8);
|
|
TQString line;
|
|
bool foundResponse = false;
|
|
bool success = false;
|
|
|
|
while (!ts.atEnd())
|
|
{
|
|
line = ts.readLine();
|
|
|
|
if (!foundResponse)
|
|
{
|
|
foundResponse = line.startsWith("#__GR2PROTO__");
|
|
}
|
|
else
|
|
{
|
|
TQStringList strlist = TQStringList::split("=", line);
|
|
if (strlist.count() == 2)
|
|
{
|
|
TQString key = strlist[0];
|
|
TQString value = strlist[1];
|
|
|
|
if (key == "status")
|
|
{
|
|
success = (value == "0");
|
|
}
|
|
else if (key.startsWith("status_text"))
|
|
{
|
|
kdDebug() << "STATUS: Create Album: " << value << endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundResponse)
|
|
{
|
|
emit signalError(i18n("Invalid response received from remote Gallery"));
|
|
return;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
emit signalError(i18n("Failed to create new album"));
|
|
return;
|
|
}
|
|
|
|
listAlbums();
|
|
}
|
|
|
|
void GalleryTalker::parseResponseAddPhoto(const TQByteArray &data)
|
|
{
|
|
TQTextStream ts(data, IO_ReadOnly );
|
|
ts.setEncoding(TQTextStream::UnicodeUTF8);
|
|
TQString line;
|
|
bool foundResponse = false;
|
|
bool success = false;
|
|
|
|
while (!ts.atEnd())
|
|
{
|
|
line = ts.readLine();
|
|
|
|
if (!foundResponse)
|
|
{
|
|
// Gallery1 sends resizing debug code sometimes so we
|
|
// have to detect things slightly differently
|
|
foundResponse = (line.startsWith("#__GR2PROTO__")
|
|
|| (line.startsWith("<br>- Resizing")
|
|
&& line.endsWith("#__GR2PROTO__")));
|
|
}
|
|
else
|
|
{
|
|
TQStringList strlist = TQStringList::split("=", line);
|
|
if (strlist.count() == 2)
|
|
{
|
|
TQString key = strlist[0];
|
|
TQString value = strlist[1];
|
|
|
|
if (key == "status")
|
|
{
|
|
success = (value == "0");
|
|
}
|
|
else if (key.startsWith("status_text"))
|
|
{
|
|
kdDebug() << "STATUS: Add Photo: " << value << endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundResponse)
|
|
{
|
|
emit signalAddPhotoFailed(i18n("Invalid response received from remote Gallery"));
|
|
return;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
emit signalAddPhotoFailed(i18n("Failed to upload photo"));
|
|
}
|
|
else
|
|
{
|
|
emit signalAddPhotoSucceeded();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#include "gallerytalker.moc"
|
|
|