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.
kipi-plugins/kipi-plugins/sync/sinks/gallery/gallerysink.cpp

687 lines
19 KiB

/* ============================================================
* File : gallerysink.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 <klocale.h>
#include <tdeio/job.h>
#include <kdebug.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <cstring>
#include <cstdio>
// LibKExiv2 includes.
#include <libkexiv2/libkexiv2.h>
#include "gallerysink.h"
#include "gallerycollection.h"
#include "galleryitem.h"
namespace KIPISyncPlugin
{
GallerySink::GallerySink(unsigned int sinkId, TQString name, TDEConfig* pConfig, KWallet::Wallet* pWallet, GalleryVersion version)
: Sink(sinkId, name, pConfig, pWallet),
mVersion(version),
mAuthToken(""),
mpJob(0),
m_loggedIn(false)
{
TQString tmp = pConfig->readEntry(TQString("URL%1").arg(sinkId));
mURL = KURL(tmp);
mUsername = pConfig->readEntry(TQString("Username%1").arg(sinkId));
if (pWallet)
pWallet->readPassword(TQString("Password%1").arg(sinkId), mPassword);
}
GallerySink::~GallerySink()
{
if (mpJob)
mpJob->kill();
}
const KIPI2::CollectionList* GallerySink::getCollections()
{
return NULL;
}
void GallerySink::Save(TDEConfig* pConfig, KWallet::Wallet* pWallet)
{
pConfig->writeEntry(TQString("Name%1").arg(mSinkId), mName);
pConfig->writeEntry(TQString("Type%1").arg(mSinkId), Type());
pConfig->writeEntry(TQString("URL%1").arg(mSinkId), TQString(mURL.url()));
pConfig->writeEntry(TQString("Username%1").arg(mSinkId), mUsername);
if (pWallet)
pWallet->writePassword(TQString("Password%1").arg(mSinkId), mPassword);
}
/*
bool GallerySink::loggedIn() const
{
return m_loggedIn;
}
*/
bool GallerySink::Connect()
{
GalleryForm form(mVersion, mAuthToken);
form.addPair("cmd", "login");
form.addPair("protocol_version", "2.3");
form.addPair("uname", mUsername);
form.addPair("password", mPassword);
TDEIO::TransferJob* job = TDEIO::http_post(mURL, form.formData(), false);
job->addMetaData("content-type", form.contentType() );
job->addMetaData("cookies", "manual");
connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
TQT_SLOT(data(TDEIO::Job*, const TQByteArray&)));
connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
TQT_SLOT(slotResult(TDEIO::Job *)));
mState = GE_LOGIN;
mpJob = job;
mBuffer.resize(0);
//emit signalBusy( true );
}
/*
void GallerySink::listAlbums()
{
GalleryForm form(mVersion, mAuthToken);
TQString task = "fetch-albums";
if (Gallery2 == mVersion)
task = "fetch-albums-prune";
form.addPair("cmd", task);
form.addPair("protocol_version", "2.3");
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, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
TQT_SLOT(data(TDEIO::Job*, const TQByteArray&)));
connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
TQT_SLOT(slotResult(TDEIO::Job *)));
mState = GE_LISTALBUMS;
mpJob = job;
mBuffer.resize(0);
emit signalBusy( true );
}
void GallerySink::listPhotos( const TQString& albumName )
{
if (mpJob)
{
mpJob->kill();
mpJob = 0;
}
GalleryForm form(mVersion, mAuthToken);
form.addPair("cmd", "fetch-album-images");
form.addPair("protocol_version", "2.3");
form.addPair("set_albumName", albumName);
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, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
TQT_SLOT(data(TDEIO::Job*, const TQByteArray&)));
connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
TQT_SLOT(slotResult(TDEIO::Job *)));
mState = GE_LISTPHOTOS;
mpJob = job;
mBuffer.resize(0);
emit signalBusy( true );
}
void GallerySink::createAlbum( const TQString& parentAlbumName,
const TQString& albumName,
const TQString& albumTitle,
const TQString& albumCaption )
{
if (mpJob)
{
mpJob->kill();
mpJob = 0;
}
GalleryForm form(mVersion, mAuthToken);
form.addPair("cmd", "new-album");
form.addPair("protocol_version", "2.3");
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);
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, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
TQT_SLOT(data(TDEIO::Job*, const TQByteArray&)));
connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
TQT_SLOT(slotResult(TDEIO::Job *)));
mState = GE_CREATEALBUM;
mpJob = job;
mBuffer.resize(0);
emit signalBusy( true );
}
bool GallerySink::addPhoto( const TQString& albumName,
const TQString& photoPath,
const TQString& caption,
bool rescale, int maxDim )
{
if (mpJob)
{
mpJob->kill();
mpJob = 0;
}
TQString path = photoPath;
TQString display_filename = TQFile::encodeName(KURL(path).filename());
GalleryForm form(mVersion, mAuthToken);
form.addPair("cmd", "add-item");
form.addPair("protocol_version", "2.3");
form.addPair("set_albumName", albumName);
if (!caption.isEmpty())
form.addPair("caption", 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, TQ_ScaleMin);
path = locateLocal("tmp", KURL(photoPath).filename());
image.save(path, TQImageIO::imageFormat(photoPath));
if ("JPEG" == TQString(TQImageIO::imageFormat(photoPath)).upper())
{
KExiv2Library::LibKExiv2 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;
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, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
TQT_SLOT(data(TDEIO::Job*, const TQByteArray&)));
connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
TQT_SLOT(slotResult(TDEIO::Job *)));
mState = GE_ADDPHOTO;
mpJob = job;
mBuffer.resize(0);
emit signalBusy( true );
return true;
}
void GallerySink::cancel()
{
if (mpJob)
{
mpJob->kill();
mpJob = 0;
}
}
void GallerySink::data(TDEIO::Job*, const TQByteArray& data)
{
if (data.isEmpty())
return;
int oldSize = mBuffer.size();
mBuffer.resize(mBuffer.size() + data.size());
memcpy(mBuffer.data()+oldSize, data.data(), data.size());
}
void GallerySink::slotResult(TDEIO::Job *job)
{
mpJob = 0;
emit signalBusy( false );
if ( job->error() )
{
if ( mState == GE_LOGIN )
emit signalLoginFailed( job->errorString() );
else if ( mState == GE_ADDPHOTO )
emit signalAddPhotoFailed( job->errorString() );
else
job->showErrorDialog( ); //m_parent
return;
}
switch(mState)
{
case(GE_LOGIN):
parseResponseLogin(mBuffer);
break;
case(GE_LISTALBUMS):
parseResponseListAlbums(mBuffer);
break;
case(GE_LISTPHOTOS):
parseResponseListPhotos(mBuffer);
break;
case(GE_CREATEALBUM):
parseResponseCreateAlbum(mBuffer);
break;
case(GE_ADDPHOTO):
parseResponseAddPhoto(mBuffer);
break;
}
if (mState == 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 GallerySink::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])
{
mAuthToken = strlist[1];
}
}
}
}
if (!foundResponse)
{
emit signalLoginFailed( i18n("Gallery URL probably incorrect"));
return;
}
if (!m_loggedIn)
{
emit signalLoginFailed(i18n("Incorrect username or password specified"));
}
}
void GallerySink::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 (Gallery2 == mVersion)
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");
}
}
}
}
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 GallerySink::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 GallerySink::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 GallerySink::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 "gallerysink.moc"