mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 18:32:51 +00:00
351 lines
10 KiB
C++
351 lines
10 KiB
C++
/* -*- c++ -*-
|
|
sievejob.h
|
|
|
|
KMail, the KDE mail client.
|
|
Copyright (c) 2002 Marc Mutz <mutz@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License,
|
|
version 2.0, as published by the Free Software Foundation.
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
|
|
*/
|
|
|
|
#include "sievejob.h"
|
|
#include "sievejob_p.h"
|
|
#include "session.h"
|
|
|
|
#include <kdebug.h>
|
|
#include <KUrl>
|
|
#include <KMessageBox>
|
|
#include <KLocalizedString>
|
|
#include <QtCore/QPointer>
|
|
|
|
using namespace KManageSieve;
|
|
|
|
QHash<KUrl, QPointer<Session> > SieveJob::Private::m_sessionPool;
|
|
|
|
Session* SieveJob::Private::sessionForUrl(const KUrl &url)
|
|
{
|
|
KUrl hostUrl( url );
|
|
hostUrl.setPath( QString() ); // remove parts not required to identify the server
|
|
QPointer<Session> sessionPtr = m_sessionPool.value( hostUrl );
|
|
if ( !sessionPtr ) {
|
|
sessionPtr = QPointer<Session>( new Session() );
|
|
m_sessionPool.insert( hostUrl, sessionPtr );
|
|
sessionPtr->connectToHost( hostUrl );
|
|
}
|
|
return sessionPtr.data();
|
|
}
|
|
|
|
static void append_lf2crlf( QByteArray &out, const QByteArray &in ) {
|
|
if ( in.isEmpty() )
|
|
return;
|
|
const unsigned int oldOutSize = out.size();
|
|
out.resize( oldOutSize + 2 * in.size() );
|
|
const char * s = in.begin();
|
|
const char * const end = in.end();
|
|
char * d = out.begin() + oldOutSize;
|
|
char last = '\0';
|
|
while ( s < end ) {
|
|
if ( *s == '\n' && last != '\r' )
|
|
*d++ = '\r';
|
|
*d++ = last = *s++;
|
|
}
|
|
out.resize( d - out.begin() );
|
|
}
|
|
|
|
void SieveJob::Private::run( Session *session )
|
|
{
|
|
switch ( mCommands.top() ) {
|
|
case Get:
|
|
{
|
|
const QString filename = mUrl.fileName( KUrl::ObeyTrailingSlash );
|
|
session->sendData( "GETSCRIPT \"" + filename.toUtf8() + "\"" );
|
|
break;
|
|
}
|
|
case Put:
|
|
{
|
|
const QString filename = mUrl.fileName( KUrl::ObeyTrailingSlash );
|
|
QByteArray encodedData;
|
|
append_lf2crlf( encodedData, mScript.toUtf8() );
|
|
session->sendData( "PUTSCRIPT \"" + filename.toUtf8() + "\" {" + QByteArray::number( encodedData.size() ) + "+}" );
|
|
session->sendData( encodedData );
|
|
break;
|
|
}
|
|
case Activate:
|
|
{
|
|
const QString filename = mUrl.fileName( KUrl::ObeyTrailingSlash );
|
|
session->sendData( "SETACTIVE \"" + filename.toUtf8() + "\"" );
|
|
break;
|
|
}
|
|
case Deactivate:
|
|
session->sendData( "SETACTIVE \"\"" );
|
|
break;
|
|
case List:
|
|
case SearchActive:
|
|
session->sendData( "LISTSCRIPTS" );
|
|
break;
|
|
case Delete:
|
|
{
|
|
const QString filename = mUrl.fileName( KUrl::ObeyTrailingSlash );
|
|
session->sendData( "DELETESCRIPT \"" + filename.toUtf8() + "\"" );
|
|
break;
|
|
}
|
|
default:
|
|
Q_ASSERT( false );
|
|
}
|
|
}
|
|
|
|
bool SieveJob::Private::handleResponse( const Response &response, const QByteArray &data )
|
|
{
|
|
const Command lastCmd = mCommands.top();
|
|
Session* session = sessionForUrl( mUrl );
|
|
|
|
QString errMsg;
|
|
// handle non-action responses
|
|
if ( response.type() != Response::Action ) {
|
|
switch ( lastCmd ) {
|
|
case Get:
|
|
mScript = QString::fromUtf8( data );
|
|
break;
|
|
case List:
|
|
case SearchActive:
|
|
{
|
|
const QString filename = QString::fromUtf8( response.key() );
|
|
mAvailableScripts.append( filename );
|
|
const bool isActive = response.extra() == "ACTIVE";
|
|
|
|
if ( isActive )
|
|
mActiveScriptName = filename;
|
|
|
|
if ( mFileExists == DontKnow && filename == mUrl.fileName() )
|
|
mFileExists = Yes;
|
|
|
|
emit q->item( q, filename, isActive );
|
|
break;
|
|
}
|
|
case Put:
|
|
if ( response.type() == Response::KeyValuePair ) {
|
|
errMsg = QString::fromUtf8( response.key() );
|
|
session->setErrorMessage( i18n("The script did not upload successfully.\n"
|
|
"This is probably due to errors in the script.\n"
|
|
"The server responded:\n%1", errMsg ) );
|
|
} else if ( response.type() == Response::Quantity ) {
|
|
errMsg = QString::fromUtf8( data );
|
|
session->setErrorMessage( i18n("The script did not upload successfully.\n"
|
|
"This is probably due to errors in the script.\n"
|
|
"The server responded:\n%1", errMsg ) );
|
|
} else {
|
|
session->setErrorMessage( i18n("The script did not upload successfully.\nThe script may contain errors.") );
|
|
}
|
|
break;
|
|
default:
|
|
kDebug() << "Unhandled response: " << response.key() << response.value() << response.extra() << data;
|
|
}
|
|
if ( lastCmd != Put )
|
|
return false; // we expect more
|
|
}
|
|
|
|
// First, let's see if we come back from a SearchActive. If so, set
|
|
// mFileExists to No if we didn't see the mUrl.fileName() during
|
|
// listDir...
|
|
if ( lastCmd == SearchActive && mFileExists == DontKnow && response.operationSuccessful() )
|
|
mFileExists = No;
|
|
|
|
// PUTSCRIPT reports the error message in an literal after the final response sometimes
|
|
if ( lastCmd == Put && response.operationResult() == Response::No ) {
|
|
if ( response.action().size() > 3 ) {
|
|
const QByteArray extra = response.action().right( response.action().size() - 3 );
|
|
sessionForUrl( mUrl )->feedBack( extra );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// prepare for next round:
|
|
mCommands.pop();
|
|
// check for errors:
|
|
if ( !response.operationSuccessful() ) {
|
|
if ( mInteractive ) {
|
|
if ( session->errorMessage().isEmpty() )
|
|
KMessageBox::error( 0, i18n( "Sieve operation failed.\n"
|
|
"The server responded:\n%1",QString::fromUtf8( response.key() ) ), i18n( "Sieve Error" ) );
|
|
else
|
|
KMessageBox::error( 0, session->errorMessage(), i18n( "Sieve Error" ) );
|
|
}
|
|
emit q->errorMessage( q, false, errMsg );
|
|
emit q->result( q, false, mScript, (mUrl.fileName() == mActiveScriptName));
|
|
|
|
if ( lastCmd == List )
|
|
emit q->gotList( q, false, mAvailableScripts, mActiveScriptName );
|
|
else
|
|
emit q->gotScript( q, false, mScript, (mUrl.fileName() == mActiveScriptName) );
|
|
|
|
q->deleteLater();
|
|
return true;
|
|
}
|
|
|
|
// check for new tasks:
|
|
if ( !mCommands.empty() ) {
|
|
// Don't fail getting a non-existent script:
|
|
if ( (mCommands.top() == Get) && (mFileExists == No) ) {
|
|
mScript.clear();
|
|
mCommands.pop();
|
|
}
|
|
}
|
|
|
|
if ( mCommands.empty() ) {
|
|
emit q->errorMessage( q, true, QString());
|
|
// was last command; report success and delete this object:
|
|
emit q->result( q, true, mScript, (mUrl.fileName() == mActiveScriptName) );
|
|
if ( lastCmd == List )
|
|
emit q->gotList( q, true, mAvailableScripts, mActiveScriptName );
|
|
else
|
|
emit q->gotScript( q, true, mScript, (mUrl.fileName() == mActiveScriptName) );
|
|
|
|
q->deleteLater();
|
|
return true;
|
|
} else {
|
|
// schedule the next command:
|
|
run( sessionForUrl( mUrl ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SieveJob::Private::killed()
|
|
{
|
|
emit q->result( q, false, mScript, (mUrl.fileName() == mActiveScriptName) );
|
|
if ( mCommands.top() == List )
|
|
emit q->gotList( q, false, mAvailableScripts, mActiveScriptName );
|
|
else
|
|
emit q->gotScript( q, false, mScript, (mUrl.fileName() == mActiveScriptName) );
|
|
}
|
|
|
|
SieveJob::SieveJob( QObject *parent )
|
|
: QObject( parent ), d( new Private( this ) )
|
|
{
|
|
}
|
|
|
|
SieveJob::~SieveJob()
|
|
{
|
|
kill();
|
|
|
|
delete d;
|
|
}
|
|
|
|
void SieveJob::kill( KJob::KillVerbosity verbosity )
|
|
{
|
|
Q_UNUSED( verbosity );
|
|
if ( d->mCommands.isEmpty() )
|
|
return; // done already
|
|
Private::sessionForUrl( d->mUrl )->killJob( this );
|
|
}
|
|
|
|
void SieveJob::setInteractive( bool interactive )
|
|
{
|
|
d->mInteractive = interactive;
|
|
}
|
|
|
|
QStringList SieveJob::sieveCapabilities() const
|
|
{
|
|
Session* session = d->sessionForUrl( d->mUrl );
|
|
if ( session )
|
|
return session->sieveExtensions();
|
|
return QStringList();
|
|
}
|
|
|
|
bool SieveJob::fileExists() const
|
|
{
|
|
return d->mFileExists;
|
|
}
|
|
|
|
SieveJob* SieveJob::put( const KUrl &destination, const QString &script,
|
|
bool makeActive, bool wasActive )
|
|
{
|
|
QStack<Private::Command> commands;
|
|
if ( makeActive )
|
|
commands.push( Private::Activate );
|
|
|
|
if ( wasActive )
|
|
commands.push( Private::Deactivate );
|
|
|
|
commands.push( Private::Put );
|
|
|
|
SieveJob *job = new SieveJob;
|
|
job->d->mUrl = destination;
|
|
job->d->mScript = script;
|
|
job->d->mCommands = commands;
|
|
|
|
Private::sessionForUrl( destination )->scheduleJob( job );
|
|
return job;
|
|
}
|
|
|
|
SieveJob* SieveJob::get( const KUrl &source )
|
|
{
|
|
QStack<Private::Command> commands;
|
|
commands.push( Private::Get );
|
|
commands.push( Private::SearchActive );
|
|
|
|
SieveJob *job = new SieveJob;
|
|
job->d->mUrl = source;
|
|
job->d->mCommands = commands;
|
|
|
|
Private::sessionForUrl( source )->scheduleJob( job );
|
|
return job;
|
|
}
|
|
|
|
SieveJob* SieveJob::list( const KUrl &source )
|
|
{
|
|
QStack<Private::Command> commands;
|
|
commands.push( Private::List );
|
|
|
|
SieveJob *job = new SieveJob;
|
|
job->d->mUrl = source;
|
|
job->d->mCommands = commands;
|
|
|
|
Private::sessionForUrl( source )->scheduleJob( job );
|
|
return job;
|
|
}
|
|
|
|
SieveJob* SieveJob::del( const KUrl &url )
|
|
{
|
|
QStack<Private::Command> commands;
|
|
commands.push( Private::Delete );
|
|
|
|
SieveJob *job = new SieveJob;
|
|
job->d->mUrl = url;
|
|
job->d->mCommands = commands;
|
|
|
|
Private::sessionForUrl( url )->scheduleJob( job );
|
|
return job;
|
|
}
|
|
|
|
SieveJob* SieveJob::deactivate( const KUrl &url )
|
|
{
|
|
QStack<Private::Command> commands;
|
|
commands.push( Private::Deactivate );
|
|
|
|
SieveJob *job = new SieveJob;
|
|
job->d->mUrl = url;
|
|
job->d->mCommands = commands;
|
|
|
|
Private::sessionForUrl( url )->scheduleJob( job );
|
|
return job;
|
|
}
|
|
|
|
SieveJob* SieveJob::activate( const KUrl &url )
|
|
{
|
|
QStack<Private::Command> commands;
|
|
commands.push( Private::Activate );
|
|
|
|
SieveJob *job = new SieveJob;
|
|
job->d->mUrl = url;
|
|
job->d->mCommands = commands;
|
|
|
|
Private::sessionForUrl( url )->scheduleJob( job );
|
|
return job;
|
|
}
|
|
|