summaryrefslogtreecommitdiffstats
path: root/kmail/vacation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/vacation.cpp')
-rw-r--r--kmail/vacation.cpp729
1 files changed, 729 insertions, 0 deletions
diff --git a/kmail/vacation.cpp b/kmail/vacation.cpp
new file mode 100644
index 00000000..af0c5e16
--- /dev/null
+++ b/kmail/vacation.cpp
@@ -0,0 +1,729 @@
+/* -*- c++ -*-
+ vacation.cpp
+
+ 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
+*/
+
+#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"