diff options
Diffstat (limited to 'kmail/vacation.cpp')
-rw-r--r-- | kmail/vacation.cpp | 729 |
1 files changed, 729 insertions, 0 deletions
diff --git a/kmail/vacation.cpp b/kmail/vacation.cpp new file mode 100644 index 000000000..af0c5e16b --- /dev/null +++ b/kmail/vacation.cpp @@ -0,0 +1,729 @@ +/* -*- c++ -*- + vacation.cpp + + KMail, the KDE mail client. + Copyright (c) 2002 Marc Mutz <[email protected]> + + 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 +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "vacation.h" +#include <limits.h> + +#include "vacationdialog.h" +#include "sievejob.h" +using KMail::SieveJob; +#include "kmkernel.h" +#include "kmmainwidget.h" +#include "accountmanager.h" +using KMail::AccountManager; +#include "kmacctimap.h" +#include "kmmessage.h" +#include "globalsettings.h" +#include <libkpimidentities/identitymanager.h> +#include <libkpimidentities/identity.h> + +#include <kmime_header_parsing.h> +using KMime::Types::AddrSpecList; + +#include <ksieve/parser.h> +#include <ksieve/scriptbuilder.h> +#include <ksieve/error.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include <qdatetime.h> + +#include <cassert> +#include <vector> +#include <map> +#include <set> + +namespace KSieveExt { + + class MultiScriptBuilder : public KSieve::ScriptBuilder { + std::vector<KSieve::ScriptBuilder*> mBuilders; + public: + MultiScriptBuilder() : KSieve::ScriptBuilder() {} + MultiScriptBuilder( KSieve::ScriptBuilder * sb1 ) + : KSieve::ScriptBuilder(), mBuilders( 1 ) + { + mBuilders[0] = sb1; + assert( sb1 ); + } + MultiScriptBuilder( KSieve::ScriptBuilder * sb1, + KSieve::ScriptBuilder * sb2 ) + : KSieve::ScriptBuilder(), mBuilders( 2 ) + { + mBuilders[0] = sb1; + mBuilders[1] = sb2; + assert( sb1 ); assert( sb2 ); + } + MultiScriptBuilder( KSieve::ScriptBuilder * sb1, + KSieve::ScriptBuilder * sb2, + KSieve::ScriptBuilder * sb3 ) + : KSieve::ScriptBuilder(), mBuilders( 3 ) + { + mBuilders[0] = sb1; + mBuilders[1] = sb2; + mBuilders[2] = sb3; + assert( sb1 ); assert( sb2 ); assert( sb3 ); + } + ~MultiScriptBuilder() {} + private: +#ifdef FOREACH +#undef FOREACH +#endif +#define FOREACH for ( std::vector<KSieve::ScriptBuilder*>::const_iterator it = mBuilders.begin(), end = mBuilders.end() ; it != end ; ++it ) (*it)-> + void commandStart( const QString & identifier ) { FOREACH commandStart( identifier ); } + void commandEnd() { FOREACH commandEnd(); } + void testStart( const QString & identifier ) { FOREACH testStart( identifier ); } + void testEnd() { FOREACH testEnd(); } + void testListStart() { FOREACH testListStart(); } + void testListEnd() { FOREACH testListEnd(); } + void blockStart() { FOREACH blockStart(); } + void blockEnd() { FOREACH blockEnd(); } + void hashComment( const QString & comment ) { FOREACH hashComment( comment ); } + void bracketComment( const QString & comment ) { FOREACH bracketComment( comment ); } + void lineFeed() { FOREACH lineFeed(); } + void error( const KSieve::Error & e ) { FOREACH error( e ); } + void finished() { FOREACH finished(); } + void taggedArgument( const QString & tag ) { FOREACH taggedArgument( tag ); } + void stringArgument( const QString & string, bool multiline, const QString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); } + void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); } + void stringListArgumentStart() { FOREACH stringListArgumentStart(); } + void stringListEntry( const QString & string, bool multiline, const QString & fixme) { FOREACH stringListEntry( string, multiline, fixme ); } + void stringListArgumentEnd() { FOREACH stringListArgumentEnd(); } +#undef FOREACH + }; + +} + +namespace { + + class GenericInformationExtractor : public KSieve::ScriptBuilder { + public: + enum BuilderMethod { + Any, + TaggedArgument, + StringArgument, + NumberArgument, + CommandStart, + CommandEnd, + TestStart, + TestEnd, + TestListStart, + TestListEnd, + BlockStart, + BlockEnd, + StringListArgumentStart, + StringListEntry, + StringListArgumentEnd + }; + + struct StateNode { + // expectation: + int depth; + BuilderMethod method; + const char * string; + // actions: + int if_found; + int if_not_found; + const char * save_tag; + }; + + const std::vector<StateNode> mNodes; + std::map<QString,QString> mResults; + std::set<unsigned int> mRecursionGuard; + unsigned int mState; + int mNestingDepth; + + public: + GenericInformationExtractor( const std::vector<StateNode> & nodes ) + : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ) {} + + const std::map<QString,QString> & results() const { return mResults; } + + private: + void process( BuilderMethod method, const QString & string=QString::null ) { + doProcess( method, string ); + mRecursionGuard.clear(); + } + void doProcess( BuilderMethod method, const QString & string ) { + mRecursionGuard.insert( mState ); + bool found = true; + const StateNode & expected = mNodes[mState]; + if ( expected.depth != -1 && mNestingDepth != expected.depth ) + found = false; + if ( expected.method != Any && method != expected.method ) + found = false; + if ( const char * str = expected.string ) + if ( string.lower() != QString::fromUtf8( str ).lower() ) + found = false; + kdDebug(5006) << ( found ? "found: " : "not found: " ) + << mState << " -> " + << ( found ? expected.if_found : expected.if_not_found ) << endl; + mState = found ? expected.if_found : expected.if_not_found ; + assert( mState < mNodes.size() ); + if ( found ) + if ( const char * save_tag = expected.save_tag ) + mResults[save_tag] = string; + if ( !found && !mRecursionGuard.count( mState ) ) { + doProcess( method, string ); + } + } + void commandStart( const QString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( CommandStart, identifier ); } + void commandEnd() { kdDebug(5006) << k_funcinfo << endl; process( CommandEnd ); } + void testStart( const QString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( TestStart, identifier ); } + void testEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestEnd ); } + void testListStart() { kdDebug(5006) << k_funcinfo << endl; process( TestListStart ); } + void testListEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestListEnd ); } + void blockStart() { kdDebug(5006) << k_funcinfo << endl; process( BlockStart ); ++mNestingDepth; } + void blockEnd() { kdDebug(5006) << k_funcinfo << endl; --mNestingDepth; process( BlockEnd ); } + void hashComment( const QString & ) { kdDebug(5006) << k_funcinfo << endl; } + void bracketComment( const QString & ) { kdDebug(5006) << k_funcinfo << endl; } + void lineFeed() { kdDebug(5006) << k_funcinfo << endl; } + void error( const KSieve::Error & ) { + kdDebug(5006) << k_funcinfo << endl; + mState = 0; + } + void finished() { kdDebug(5006) << k_funcinfo << endl; } + + void taggedArgument( const QString & tag ) { kdDebug(5006) << k_funcinfo << endl; process( TaggedArgument, tag ); } + void stringArgument( const QString & string, bool, const QString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringArgument, string ); } + void numberArgument( unsigned long number, char ) { kdDebug(5006) << k_funcinfo << endl; process( NumberArgument, QString::number( number ) ); } + void stringListArgumentStart() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentStart ); } + void stringListEntry( const QString & string, bool, const QString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringListEntry, string ); } + void stringListArgumentEnd() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentEnd ); } + }; + + typedef GenericInformationExtractor GIE; + static const GenericInformationExtractor::StateNode spamNodes[] = { + { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0 + { 0, GIE::TestStart, "header", 2, 0, 0 }, // 1 + { 0, GIE::TaggedArgument, "contains", 3, 0, 0 }, // 2 + + // accept both string and string-list: + { 0, GIE::StringArgument, "x-spam-flag", 9, 4, "x-spam-flag" }, // 3 + { 0, GIE::StringListArgumentStart, 0, 5, 0, 0 }, // 4 + { 0, GIE::StringListEntry, "x-spam-flag", 6, 7, "x-spam-flag" }, // 5 + { 0, GIE::StringListEntry, 0, 6, 8, 0 }, // 6 + { 0, GIE::StringListArgumentEnd, 0, 0, 5, 0 }, // 7 + { 0, GIE::StringListArgumentEnd, 0, 9, 0, 0 }, // 8 + + // accept both string and string-list: + { 0, GIE::StringArgument, "yes", 15, 10, "spam-flag-yes" }, // 9 + { 0, GIE::StringListArgumentStart, 0, 11, 0, 0 }, // 10 + { 0, GIE::StringListEntry, "yes", 12, 13, "spam-flag-yes" }, // 11 + { 0, GIE::StringListEntry, 0, 12, 14, 0 }, // 12 + { 0, GIE::StringListArgumentEnd, 0, 0, 11, 0 }, // 13 + { 0, GIE::StringListArgumentEnd, 0, 15, 0, 0 }, // 14 + + { 0, GIE::TestEnd, 0, 16, 0, 0 }, // 15 + + // block of command, find "stop", take nested if's into account: + { 0, GIE::BlockStart, 0, 17, 0, 0 }, // 16 + { 1, GIE::CommandStart, "stop", 20, 19, "stop" }, // 17 + { -1, GIE::Any, 0, 17, 0, 0 }, // 18 + { 0, GIE::BlockEnd, 0, 0, 18, 0 }, // 19 + + { -1, GIE::Any, 0, 20, 20, 0 }, // 20 end state + }; + static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ; + + class SpamDataExtractor : public GenericInformationExtractor { + public: + SpamDataExtractor() + : GenericInformationExtractor( std::vector<StateNode>( spamNodes, spamNodes + numSpamNodes ) ) + { + + } + + bool found() const { + return mResults.count( "x-spam-flag" ) && + mResults.count( "spam-flag-yes" ) && + mResults.count( "stop" ) ; + } + }; + + // to understand this table, study the output of + // libksieve/tests/parsertest + // 'if not address :domain :contains ["from"] ["mydomain.org"] { keep; stop; }' + static const GenericInformationExtractor::StateNode domainNodes[] = { + { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0 + { 0, GIE::TestStart, "not", 2, 0, 0, }, // 1 + { 0, GIE::TestStart, "address", 3, 0, 0 }, // 2 + + // :domain and :contains in arbitrary order: + { 0, GIE::TaggedArgument, "domain", 4, 5, 0 }, // 3 + { 0, GIE::TaggedArgument, "contains", 7, 0, 0 }, // 4 + { 0, GIE::TaggedArgument, "contains", 6, 0, 0 }, // 5 + { 0, GIE::TaggedArgument, "domain", 7, 0, 0 }, // 6 + + // accept both string and string-list: + { 0, GIE::StringArgument, "from", 13, 8, "from" }, // 7 + { 0, GIE::StringListArgumentStart, 0, 9, 0, 0 }, // 8 + { 0, GIE::StringListEntry, "from", 10, 11, "from" }, // 9 + { 0, GIE::StringListEntry, 0, 10, 12, 0 }, // 10 + { 0, GIE::StringListArgumentEnd, 0, 0, 9, 0 }, // 11 + { 0, GIE::StringListArgumentEnd, 0, 13, 0, 0 }, // 12 + + // string: save, string-list: save last + { 0, GIE::StringArgument, 0, 17, 14, "domainName" }, // 13 + { 0, GIE::StringListArgumentStart, 0, 15, 0, 0 }, // 14 + { 0, GIE::StringListEntry, 0, 15, 16, "domainName" }, // 15 + { 0, GIE::StringListArgumentEnd, 0, 17, 0, 0 }, // 16 + + { 0, GIE::TestEnd, 0, 18, 0, 0 }, // 17 + { 0, GIE::TestEnd, 0, 19, 0, 0 }, // 18 + + // block of commands, find "stop", take nested if's into account: + { 0, GIE::BlockStart, 0, 20, 0, 0 }, // 19 + { 1, GIE::CommandStart, "stop", 23, 22, "stop" }, // 20 + { -1, GIE::Any, 0, 20, 0, 0 }, // 21 + { 0, GIE::BlockEnd, 0, 0, 21, 0 }, // 22 + + { -1, GIE::Any, 0, 23, 23, 0 } // 23 end state + }; + static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ; + + class DomainRestrictionDataExtractor : public GenericInformationExtractor { + public: + DomainRestrictionDataExtractor() + : GenericInformationExtractor( std::vector<StateNode>( domainNodes, domainNodes+numDomainNodes ) ) + { + + } + + QString domainName() /*not const, since map::op[] isn't const*/ { + return mResults.count( "stop" ) && mResults.count( "from" ) + ? mResults["domainName"] : QString::null ; + } + }; + + class VacationDataExtractor : public KSieve::ScriptBuilder { + enum Context { + None = 0, + // command itself: + VacationCommand, + // tagged args: + Days, Addresses + }; + public: + VacationDataExtractor() + : KSieve::ScriptBuilder(), + mContext( None ), mNotificationInterval( 0 ) + { + kdDebug(5006) << "VacationDataExtractor instantiated" << endl; + } + virtual ~VacationDataExtractor() {} + + int notificationInterval() const { return mNotificationInterval; } + const QString & messageText() const { return mMessageText; } + const QStringList & aliases() const { return mAliases; } + + private: + void commandStart( const QString & identifier ) { + kdDebug( 5006 ) << "VacationDataExtractor::commandStart( \"" << identifier << "\" )" << endl; + if ( identifier != "vacation" ) + return; + reset(); + mContext = VacationCommand; + } + + void commandEnd() { + kdDebug( 5006 ) << "VacationDataExtractor::commandEnd()" << endl; + mContext = None; + } + + void testStart( const QString & ) {} + void testEnd() {} + void testListStart() {} + void testListEnd() {} + void blockStart() {} + void blockEnd() {} + void hashComment( const QString & ) {} + void bracketComment( const QString & ) {} + void lineFeed() {} + void error( const KSieve::Error & e ) { + kdDebug( 5006 ) << "VacationDataExtractor::error() ### " + << e.asString() << " @ " << e.line() << "," << e.column() + << endl; + } + void finished() {} + + void taggedArgument( const QString & tag ) { + kdDebug( 5006 ) << "VacationDataExtractor::taggedArgument( \"" << tag << "\" )" << endl; + if ( mContext != VacationCommand ) + return; + if ( tag == "days" ) + mContext = Days; + else if ( tag == "addresses" ) + mContext = Addresses; + } + + void stringArgument( const QString & string, bool, const QString & ) { + kdDebug( 5006 ) << "VacationDataExtractor::stringArgument( \"" << string << "\" )" << endl; + if ( mContext == Addresses ) { + mAliases.push_back( string ); + mContext = VacationCommand; + } else if ( mContext == VacationCommand ) { + mMessageText = string; + mContext = VacationCommand; + } + } + + void numberArgument( unsigned long number, char ) { + kdDebug( 5006 ) << "VacationDataExtractor::numberArgument( \"" << number << "\" )" << endl; + if ( mContext != Days ) + return; + if ( number > INT_MAX ) + mNotificationInterval = INT_MAX; + else + mNotificationInterval = number; + mContext = VacationCommand; + } + + void stringListArgumentStart() {} + void stringListEntry( const QString & string, bool, const QString & ) { + kdDebug( 5006 ) << "VacationDataExtractor::stringListEntry( \"" << string << "\" )" << endl; + if ( mContext != Addresses ) + return; + mAliases.push_back( string ); + } + void stringListArgumentEnd() { + kdDebug( 5006 ) << "VacationDataExtractor::stringListArgumentEnd()" << endl; + if ( mContext != Addresses ) + return; + mContext = VacationCommand; + } + + private: + Context mContext; + int mNotificationInterval; + QString mMessageText; + QStringList mAliases; + + void reset() { + kdDebug(5006) << "VacationDataExtractor::reset()" << endl; + mContext = None; + mNotificationInterval = 0; + mAliases.clear(); + mMessageText = QString::null; + } + }; + +} + +namespace KMail { + + Vacation::Vacation( QObject * parent, bool checkOnly, const char * name ) + : QObject( parent, name ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false ), mCheckOnly( checkOnly ) + { + mUrl = findURL(); + kdDebug(5006) << "Vacation: found url \"" << mUrl.prettyURL() << "\"" << endl; + if ( mUrl.isEmpty() ) // nothing to do... + return; + mSieveJob = SieveJob::get( mUrl, !checkOnly ); + connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)), + SLOT(slotGetResult(KMail::SieveJob*,bool,const QString&,bool)) ); + } + + Vacation::~Vacation() { + if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0; + delete mDialog; mDialog = 0; + kdDebug(5006) << "~Vacation()" << endl; + } + + static inline QString dotstuff( QString s ) { + if ( s.startsWith( "." ) ) + return '.' + s.replace( "\n.", "\n.." ); + else + return s.replace( "\n.", "\n.." ); + } + + QString Vacation::composeScript( const QString & messageText, + int notificationInterval, + const AddrSpecList & addrSpecs, + bool sendForSpam, const QString & domain ) + { + QString addressesArgument; + QStringList aliases; + if ( !addrSpecs.empty() ) { + addressesArgument += ":addresses [ "; + QStringList sl; + for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != addrSpecs.end() ; ++it ) { + sl.push_back( '"' + (*it).asString().replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"' ); + aliases.push_back( (*it).asString() ); + } + addressesArgument += sl.join( ", " ) + " ] "; + } + QString script = QString::fromLatin1("require \"vacation\";\n\n" ); + if ( !sendForSpam ) + script += QString::fromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\"" + " { keep; stop; }\n" ); // FIXME? + + if ( !domain.isEmpty() ) // FIXME + script += QString::fromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).arg( domain ); + + script += "vacation "; + script += addressesArgument; + if ( notificationInterval > 0 ) + script += QString::fromLatin1(":days %1 ").arg( notificationInterval ); + script += QString::fromLatin1("text:\n"); + script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText ); + script += QString::fromLatin1( "\n.\n;\n" ); + return script; + } + + static KURL findUrlForAccount( const KMail::ImapAccountBase * a ) { + assert( a ); + const SieveConfig sieve = a->sieveConfig(); + if ( !sieve.managesieveSupported() ) + return KURL(); + if ( sieve.reuseConfig() ) { + // assemble Sieve url from the settings of the account: + KURL u; + u.setProtocol( "sieve" ); + u.setHost( a->host() ); + u.setUser( a->login() ); + u.setPass( a->passwd() ); + u.setPort( sieve.port() ); + u.setQuery( "x-mech=" + (a->auth() == "*" ? "PLAIN" : a->auth()) ); //translate IMAP LOGIN to PLAIN + u.setFileName( sieve.vacationFileName() ); + return u; + } else { + KURL u = sieve.alternateURL(); + u.setFileName( sieve.vacationFileName() ); + return u; + } + } + + KURL Vacation::findURL() const { + AccountManager * am = kmkernel->acctMgr(); + assert( am ); + for ( KMAccount * a = am->first() ; a ; a = am->next() ) + if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) { + KURL u = findUrlForAccount( iab ); + if ( !u.isEmpty() ) + return u; + } + return KURL(); + } + + bool Vacation::parseScript( const QString & script, QString & messageText, + int & notificationInterval, QStringList & aliases, + bool & sendForSpam, QString & domainName ) { + if ( script.stripWhiteSpace().isEmpty() ) { + messageText = defaultMessageText(); + notificationInterval = defaultNotificationInterval(); + aliases = defaultMailAliases(); + sendForSpam = defaultSendForSpam(); + domainName = defaultDomainName(); + return true; + } + + // The stripWhiteSpace() call below prevents parsing errors. The + // slave somehow omits the last \n, which results in a lone \r at + // the end, leading to a parse error. + const QCString scriptUTF8 = script.stripWhiteSpace().utf8(); + kdDebug(5006) << "scriptUtf8 = \"" + scriptUTF8 + "\"" << endl; + KSieve::Parser parser( scriptUTF8.begin(), + scriptUTF8.begin() + scriptUTF8.length() ); + VacationDataExtractor vdx; + SpamDataExtractor sdx; + DomainRestrictionDataExtractor drdx; + KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx ); + parser.setScriptBuilder( &tsb ); + if ( !parser.parse() ) + return false; + messageText = vdx.messageText().stripWhiteSpace(); + notificationInterval = vdx.notificationInterval(); + aliases = vdx.aliases(); + if ( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ) { + sendForSpam = !sdx.found(); + domainName = drdx.domainName(); + } + return true; + } + + QString Vacation::defaultMessageText() { + return i18n("I am out of office till %1.\n" + "\n" + "In urgent cases, please contact Mrs. <vacation replacement>\n" + "\n" + "email: <email address of vacation replacement>\n" + "phone: +49 711 1111 11\n" + "fax.: +49 711 1111 12\n" + "\n" + "Yours sincerely,\n" + "-- <enter your name and email address here>\n") + .arg( KGlobal::locale()->formatDate( QDate::currentDate().addDays( 1 ) ) ); + } + + int Vacation::defaultNotificationInterval() { + return 7; // days + } + + QStringList Vacation::defaultMailAliases() { + QStringList sl; + for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ; + it != kmkernel->identityManager()->end() ; ++it ) + if ( !(*it).emailAddr().isEmpty() ) + sl.push_back( (*it).emailAddr() ); + return sl; + } + + bool Vacation::defaultSendForSpam() { + return GlobalSettings::outOfOfficeReactToSpam(); + } + + QString Vacation::defaultDomainName() { + return GlobalSettings::outOfOfficeDomain(); + } + + void Vacation::slotGetResult( SieveJob * job, bool success, + const QString & script, bool active ) { + kdDebug(5006) << "Vacation::slotGetResult( ??, " << success + << ", ?, " << active << " )" << endl + << "script:" << endl + << script << endl; + mSieveJob = 0; // job deletes itself after returning from this slot! + + if ( !mCheckOnly && mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() && + !job->sieveCapabilities().contains("vacation") ) { + KMessageBox::sorry( 0, i18n("Your server did not list \"vacation\" in " + "its list of supported Sieve extensions;\n" + "without it, KMail cannot install out-of-" + "office replies for you.\n" + "Please contact you system administrator.") ); + emit result( false ); + return; + } + + if ( !mDialog && !mCheckOnly ) + mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false ); + + QString messageText = defaultMessageText(); + int notificationInterval = defaultNotificationInterval(); + QStringList aliases = defaultMailAliases(); + bool sendForSpam = defaultSendForSpam(); + QString domainName = defaultDomainName(); + if ( !success ) active = false; // default to inactive + + if ( !mCheckOnly && ( !success || !parseScript( script, messageText, notificationInterval, aliases, sendForSpam, domainName ) ) ) + KMessageBox::information( 0, i18n("Someone (probably you) changed the " + "vacation script on the server.\n" + "KMail is no longer able to determine " + "the parameters for the autoreplies.\n" + "Default values will be used." ) ); + + mWasActive = active; + if ( mDialog ) { + mDialog->setActivateVacation( active ); + mDialog->setMessageText( messageText ); + mDialog->setNotificationInterval( notificationInterval ); + mDialog->setMailAliases( aliases.join(", ") ); + mDialog->setSendForSpam( sendForSpam ); + mDialog->setDomainName( domainName ); + mDialog->enableDomainAndSendForSpam( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ); + + connect( mDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) ); + connect( mDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCancel()) ); + connect( mDialog, SIGNAL(defaultClicked()), SLOT(slotDialogDefaults()) ); + + mDialog->show(); + } + + emit scriptActive( mWasActive ); + if ( mCheckOnly && mWasActive ) { + if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n" + "Do you want to edit it?"), i18n("Out-of-office reply still active"), + KGuiItem( i18n( "Edit"), "edit" ), KGuiItem( i18n("Ignore"), "button_cancel" ) ) + == KMessageBox::Yes ) { + kmkernel->getKMMainWidget()->slotEditVacation(); + } + } + } + + void Vacation::slotDialogDefaults() { + if ( !mDialog ) + return; + mDialog->setActivateVacation( true ); + mDialog->setMessageText( defaultMessageText() ); + mDialog->setNotificationInterval( defaultNotificationInterval() ); + mDialog->setMailAliases( defaultMailAliases().join(", ") ); + mDialog->setSendForSpam( defaultSendForSpam() ); + mDialog->setDomainName( defaultDomainName() ); + } + + void Vacation::slotDialogOk() { + kdDebug(5006) << "Vacation::slotDialogOk()" << endl; + // compose a new script: + const QString script = composeScript( mDialog->messageText(), + mDialog->notificationInterval(), + mDialog->mailAliases(), + mDialog->sendForSpam(), + mDialog->domainName() ); + const bool active = mDialog->activateVacation(); + emit scriptActive( active ); + + kdDebug(5006) << "script:" << endl << script << endl; + + // and commit the dialog's settings to the server: + mSieveJob = SieveJob::put( mUrl, script, active, mWasActive ); + connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)), + active + ? SLOT(slotPutActiveResult(KMail::SieveJob*,bool)) + : SLOT(slotPutInactiveResult(KMail::SieveJob*,bool)) ); + + // destroy the dialog: + mDialog->delayedDestruct(); + mDialog = 0; + } + + void Vacation::slotDialogCancel() { + kdDebug(5006) << "Vacation::slotDialogCancel()" << endl; + mDialog->delayedDestruct(); + mDialog = 0; + emit result( false ); + } + + void Vacation::slotPutActiveResult( SieveJob * job, bool success ) { + handlePutResult( job, success, true ); + } + + void Vacation::slotPutInactiveResult( SieveJob * job, bool success ) { + handlePutResult( job, success, false ); + } + + void Vacation::handlePutResult( SieveJob *, bool success, bool activated ) { + if ( success ) + KMessageBox::information( 0, activated + ? i18n("Sieve script installed successfully on the server.\n" + "Out of Office reply is now active.") + : i18n("Sieve script installed successfully on the server.\n" + "Out of Office reply has been deactivated.") ); + + kdDebug(5006) << "Vacation::handlePutResult( ???, " << success << ", ? )" + << endl; + mSieveJob = 0; // job deletes itself after returning from this slot! + emit result( success ); + emit scriptActive( activated ); + } + + +} // namespace KMail + +#include "vacation.moc" |