/* -*- 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 <tqdatetime.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 TQString & identifier ) { FOREACH commandStart( identifier ); } void commandEnd() { FOREACH commandEnd(); } void testStart( const TQString & 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 TQString & comment ) { FOREACH hashComment( comment ); } void bracketComment( const TQString & comment ) { FOREACH bracketComment( comment ); } void lineFeed() { FOREACH lineFeed(); } void error( const KSieve::Error & e ) { FOREACH error( e ); } void finished() { FOREACH finished(); } void taggedArgument( const TQString & tag ) { FOREACH taggedArgument( tag ); } void stringArgument( const TQString & string, bool multiline, const TQString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); } void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); } void stringListArgumentStart() { FOREACH stringListArgumentStart(); } void stringListEntry( const TQString & string, bool multiline, const TQString & 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<TQString,TQString> 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<TQString,TQString> & results() const { return mResults; } private: void process( BuilderMethod method, const TQString & string=TQString() ) { doProcess( method, string ); mRecursionGuard.clear(); } void doProcess( BuilderMethod method, const TQString & 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() != TQString::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 TQString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( CommandStart, identifier ); } void commandEnd() { kdDebug(5006) << k_funcinfo << endl; process( CommandEnd ); } void testStart( const TQString & 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 TQString & ) { kdDebug(5006) << k_funcinfo << endl; } void bracketComment( const TQString & ) { 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 TQString & tag ) { kdDebug(5006) << k_funcinfo << endl; process( TaggedArgument, tag ); } void stringArgument( const TQString & string, bool, const TQString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringArgument, string ); } void numberArgument( unsigned long number, char ) { kdDebug(5006) << k_funcinfo << endl; process( NumberArgument, TQString::number( number ) ); } void stringListArgumentStart() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentStart ); } void stringListEntry( const TQString & string, bool, const TQString & ) { 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 ) ) { } TQString domainName() /*not const, since map::op[] isn't const*/ { return mResults.count( "stop" ) && mResults.count( "from" ) ? mResults["domainName"] : TQString() ; } }; 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 TQString & messageText() const { return mMessageText; } const TQStringList & aliases() const { return mAliases; } private: void commandStart( const TQString & 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 TQString & ) {} void testEnd() {} void testListStart() {} void testListEnd() {} void blockStart() {} void blockEnd() {} void hashComment( const TQString & ) {} void bracketComment( const TQString & ) {} void lineFeed() {} void error( const KSieve::Error & e ) { kdDebug( 5006 ) << "VacationDataExtractor::error() ### " << e.asString() << " @ " << e.line() << "," << e.column() << endl; } void finished() {} void taggedArgument( const TQString & 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 TQString & string, bool, const TQString & ) { 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 TQString & string, bool, const TQString & ) { 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; TQString mMessageText; TQStringList mAliases; void reset() { kdDebug(5006) << "VacationDataExtractor::reset()" << endl; mContext = None; mNotificationInterval = 0; mAliases.clear(); mMessageText = TQString(); } }; } namespace KMail { Vacation::Vacation( TQObject * parent, bool checkOnly, const char * name ) : TQObject( 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, TQT_SIGNAL(gotScript(KMail::SieveJob*,bool,const TQString&,bool)), TQT_SLOT(slotGetResult(KMail::SieveJob*,bool,const TQString&,bool)) ); } Vacation::~Vacation() { if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0; delete mDialog; mDialog = 0; kdDebug(5006) << "~Vacation()" << endl; } static inline TQString dotstuff( TQString s ) { if ( s.startsWith( "." ) ) return '.' + s.replace( "\n.", "\n.." ); else return s.replace( "\n.", "\n.." ); } TQString Vacation::composeScript( const TQString & messageText, int notificationInterval, const AddrSpecList & addrSpecs, bool sendForSpam, const TQString & domain ) { TQString addressesArgument; TQStringList aliases; if ( !addrSpecs.empty() ) { addressesArgument += ":addresses [ "; TQStringList 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( ", " ) + " ] "; } TQString script = TQString::tqfromLatin1("require \"vacation\";\n\n" ); if ( !sendForSpam ) script += TQString::tqfromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\"" " { keep; stop; }\n" ); // FIXME? if ( !domain.isEmpty() ) // FIXME script += TQString::tqfromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).tqarg( domain ); script += "vacation "; script += addressesArgument; if ( notificationInterval > 0 ) script += TQString::tqfromLatin1(":days %1 ").tqarg( notificationInterval ); script += TQString::tqfromLatin1("text:\n"); script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText ); script += TQString::tqfromLatin1( "\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.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() ); //translate IMAP LOGIN to PLAIN if ( !a->useSSL() && !a->useTLS() ) u.addQueryItem( "x-allow-unencrypted", "true" ); u.setFileName( sieve.vacationFileName() ); return u; } else { KURL u = sieve.alternateURL(); if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() ) u.addQueryItem( "x-allow-unencrypted", "true" ); 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 TQString & script, TQString & messageText, int & notificationInterval, TQStringList & aliases, bool & sendForSpam, TQString & 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 TQCString 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; } TQString 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") .tqarg( KGlobal::locale()->formatDate( TQDate::tqcurrentDate().addDays( 1 ) ) ); } int Vacation::defaultNotificationInterval() { return 7; // days } TQStringList Vacation::defaultMailAliases() { TQStringList sl; for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ; it != kmkernel->identityManager()->end() ; ++it ) { if ( !(*it).primaryEmailAddress().isEmpty() ) sl.push_back( (*it).primaryEmailAddress() ); sl += (*it).emailAliases(); } return sl; } bool Vacation::defaultSendForSpam() { return GlobalSettings::outOfOfficeReactToSpam(); } TQString Vacation::defaultDomainName() { return GlobalSettings::outOfOfficeDomain(); } void Vacation::slotGetResult( SieveJob * job, bool success, const TQString & 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 ); TQString messageText = defaultMessageText(); int notificationInterval = defaultNotificationInterval(); TQStringList aliases = defaultMailAliases(); bool sendForSpam = defaultSendForSpam(); TQString 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, TQT_SIGNAL(okClicked()), TQT_SLOT(slotDialogOk()) ); connect( mDialog, TQT_SIGNAL(cancelClicked()), TQT_SLOT(slotDialogCancel()) ); connect( mDialog, TQT_SIGNAL(defaultClicked()), TQT_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() ); mDialog->setDomainCheck( false ); } void Vacation::slotDialogOk() { kdDebug(5006) << "Vacation::slotDialogOk()" << endl; // compose a new script: const TQString 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, TQT_SIGNAL(gotScript(KMail::SieveJob*,bool,const TQString&,bool)), active ? TQT_SLOT(slotPutActiveResult(KMail::SieveJob*,bool)) : TQT_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"