kcmshell renamed to kcmshell4 to fix co-installability between kdelibs3 and kdebase4...
[kdepim.git] / kmail / vacation.cpp
bloba43bea933e539957fd47560e1a5518a0b6e83f3a
1 /* -*- c++ -*-
2 vacation.cpp
4 KMail, the KDE mail client.
5 Copyright (c) 2002 Marc Mutz <mutz@kde.org>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License,
9 version 2.0, as published by the Free Software Foundation.
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
15 #include "vacation.h"
16 #include <limits.h>
18 #include "vacationdialog.h"
19 #include "sievejob.h"
20 //Added by qt3to4:
21 #include <QByteArray>
22 using KMail::SieveJob;
23 #include "kmkernel.h"
24 #include "accountmanager.h"
25 using KMail::AccountManager;
26 #include "kmacctimap.h"
27 #include <kpimidentities/identitymanager.h>
28 #include <kpimidentities/identity.h>
29 #include "kmmessage.h"
30 #include "globalsettings.h"
32 #include <kmime/kmime_header_parsing.h>
33 using KMime::Types::AddrSpecList;
35 #include <ksieve/parser.h>
36 #include <ksieve/scriptbuilder.h>
37 #include <ksieve/error.h>
39 #include <kglobal.h>
40 #include <klocale.h>
41 #include <kmessagebox.h>
42 #include <kdebug.h>
44 #include <QDateTime>
46 #include <cassert>
47 #include <vector>
48 #include <map>
49 #include <set>
51 namespace KSieveExt {
53 class MultiScriptBuilder : public KSieve::ScriptBuilder {
54 std::vector<KSieve::ScriptBuilder*> mBuilders;
55 public:
56 MultiScriptBuilder() : KSieve::ScriptBuilder() {}
57 MultiScriptBuilder( KSieve::ScriptBuilder * sb1 )
58 : KSieve::ScriptBuilder(), mBuilders( 1 )
60 mBuilders[0] = sb1;
61 assert( sb1 );
63 MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
64 KSieve::ScriptBuilder * sb2 )
65 : KSieve::ScriptBuilder(), mBuilders( 2 )
67 mBuilders[0] = sb1;
68 mBuilders[1] = sb2;
69 assert( sb1 ); assert( sb2 );
71 MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
72 KSieve::ScriptBuilder * sb2,
73 KSieve::ScriptBuilder * sb3 )
74 : KSieve::ScriptBuilder(), mBuilders( 3 )
76 mBuilders[0] = sb1;
77 mBuilders[1] = sb2;
78 mBuilders[2] = sb3;
79 assert( sb1 ); assert( sb2 ); assert( sb3 );
81 ~MultiScriptBuilder() {}
82 private:
83 #ifdef FOREACH
84 #undef FOREACH
85 #endif
86 #define FOREACH for ( std::vector<KSieve::ScriptBuilder*>::const_iterator it = mBuilders.begin(), end = mBuilders.end() ; it != end ; ++it ) (*it)->
87 void commandStart( const QString & identifier ) { FOREACH commandStart( identifier ); }
88 void commandEnd() { FOREACH commandEnd(); }
89 void testStart( const QString & identifier ) { FOREACH testStart( identifier ); }
90 void testEnd() { FOREACH testEnd(); }
91 void testListStart() { FOREACH testListStart(); }
92 void testListEnd() { FOREACH testListEnd(); }
93 void blockStart() { FOREACH blockStart(); }
94 void blockEnd() { FOREACH blockEnd(); }
95 void hashComment( const QString & comment ) { FOREACH hashComment( comment ); }
96 void bracketComment( const QString & comment ) { FOREACH bracketComment( comment ); }
97 void lineFeed() { FOREACH lineFeed(); }
98 void error( const KSieve::Error & e ) { FOREACH error( e ); }
99 void finished() { FOREACH finished(); }
100 void taggedArgument( const QString & tag ) { FOREACH taggedArgument( tag ); }
101 void stringArgument( const QString & string, bool multiline, const QString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); }
102 void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); }
103 void stringListArgumentStart() { FOREACH stringListArgumentStart(); }
104 void stringListEntry( const QString & string, bool multiline, const QString & fixme) { FOREACH stringListEntry( string, multiline, fixme ); }
105 void stringListArgumentEnd() { FOREACH stringListArgumentEnd(); }
106 #undef FOREACH
111 namespace {
113 class GenericInformationExtractor : public KSieve::ScriptBuilder {
114 public:
115 enum BuilderMethod {
116 Any,
117 TaggedArgument,
118 StringArgument,
119 NumberArgument,
120 CommandStart,
121 CommandEnd,
122 TestStart,
123 TestEnd,
124 TestListStart,
125 TestListEnd,
126 BlockStart,
127 BlockEnd,
128 StringListArgumentStart,
129 StringListEntry,
130 StringListArgumentEnd
133 struct StateNode {
134 // expectation:
135 int depth;
136 BuilderMethod method;
137 const char * string;
138 // actions:
139 int if_found;
140 int if_not_found;
141 const char * save_tag;
144 const std::vector<StateNode> mNodes;
145 std::map<QString,QString> mResults;
146 std::set<unsigned int> mRecursionGuard;
147 unsigned int mState;
148 int mNestingDepth;
150 public:
151 GenericInformationExtractor( const std::vector<StateNode> & nodes )
152 : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ) {}
154 const std::map<QString,QString> & results() const { return mResults; }
156 private:
157 void process( BuilderMethod method, const QString & string=QString() ) {
158 doProcess( method, string );
159 mRecursionGuard.clear();
161 void doProcess( BuilderMethod method, const QString & string ) {
162 mRecursionGuard.insert( mState );
163 bool found = true;
164 const StateNode & expected = mNodes[mState];
165 if ( expected.depth != -1 && mNestingDepth != expected.depth )
166 found = false;
167 if ( expected.method != Any && method != expected.method )
168 found = false;
169 if ( const char * str = expected.string )
170 if ( string.toLower() != QString::fromUtf8( str ).toLower() )
171 found = false;
172 kDebug(5006) << ( found ?"found:" :"not found:" )
173 << mState << "->"
174 << ( found ? expected.if_found : expected.if_not_found );
175 mState = found ? expected.if_found : expected.if_not_found ;
176 assert( mState < mNodes.size() );
177 if ( found )
178 if ( const char * save_tag = expected.save_tag )
179 mResults[save_tag] = string;
180 if ( !found && !mRecursionGuard.count( mState ) ) {
181 doProcess( method, string );
184 void commandStart( const QString & identifier ) { kDebug(5006) ; process( CommandStart, identifier ); }
185 void commandEnd() { kDebug(5006) ; process( CommandEnd ); }
186 void testStart( const QString & identifier ) { kDebug(5006) ; process( TestStart, identifier ); }
187 void testEnd() { kDebug(5006) ; process( TestEnd ); }
188 void testListStart() { kDebug(5006) ; process( TestListStart ); }
189 void testListEnd() { kDebug(5006) ; process( TestListEnd ); }
190 void blockStart() { kDebug(5006) ; process( BlockStart ); ++mNestingDepth; }
191 void blockEnd() { kDebug(5006) ; --mNestingDepth; process( BlockEnd ); }
192 void hashComment( const QString & ) { kDebug(5006) ; }
193 void bracketComment( const QString & ) { kDebug(5006) ; }
194 void lineFeed() { kDebug(5006) ; }
195 void error( const KSieve::Error & ) {
196 kDebug(5006) ;
197 mState = 0;
199 void finished() { kDebug(5006) ; }
201 void taggedArgument( const QString & tag ) { kDebug(5006) ; process( TaggedArgument, tag ); }
202 void stringArgument( const QString & string, bool, const QString & ) { kDebug(5006) ; process( StringArgument, string ); }
203 void numberArgument( unsigned long number, char ) { kDebug(5006) ; process( NumberArgument, QString::number( number ) ); }
204 void stringListArgumentStart() { kDebug(5006) ; process( StringListArgumentStart ); }
205 void stringListEntry( const QString & string, bool, const QString & ) { kDebug(5006) ; process( StringListEntry, string ); }
206 void stringListArgumentEnd() { kDebug(5006) ; process( StringListArgumentEnd ); }
209 typedef GenericInformationExtractor GIE;
210 static const GenericInformationExtractor::StateNode spamNodes[] = {
211 { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0
212 { 0, GIE::TestStart, "header", 2, 0, 0 }, // 1
213 { 0, GIE::TaggedArgument, "contains", 3, 0, 0 }, // 2
215 // accept both string and string-list:
216 { 0, GIE::StringArgument, "x-spam-flag", 9, 4, "x-spam-flag" }, // 3
217 { 0, GIE::StringListArgumentStart, 0, 5, 0, 0 }, // 4
218 { 0, GIE::StringListEntry, "x-spam-flag", 6, 7, "x-spam-flag" }, // 5
219 { 0, GIE::StringListEntry, 0, 6, 8, 0 }, // 6
220 { 0, GIE::StringListArgumentEnd, 0, 0, 5, 0 }, // 7
221 { 0, GIE::StringListArgumentEnd, 0, 9, 0, 0 }, // 8
223 // accept both string and string-list:
224 { 0, GIE::StringArgument, "yes", 15, 10, "spam-flag-yes" }, // 9
225 { 0, GIE::StringListArgumentStart, 0, 11, 0, 0 }, // 10
226 { 0, GIE::StringListEntry, "yes", 12, 13, "spam-flag-yes" }, // 11
227 { 0, GIE::StringListEntry, 0, 12, 14, 0 }, // 12
228 { 0, GIE::StringListArgumentEnd, 0, 0, 11, 0 }, // 13
229 { 0, GIE::StringListArgumentEnd, 0, 15, 0, 0 }, // 14
231 { 0, GIE::TestEnd, 0, 16, 0, 0 }, // 15
233 // block of command, find "stop", take nested if's into account:
234 { 0, GIE::BlockStart, 0, 17, 0, 0 }, // 16
235 { 1, GIE::CommandStart, "stop", 20, 19, "stop" }, // 17
236 { -1, GIE::Any, 0, 17, 0, 0 }, // 18
237 { 0, GIE::BlockEnd, 0, 0, 18, 0 }, // 19
239 { -1, GIE::Any, 0, 20, 20, 0 }, // 20 end state
241 static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ;
243 class SpamDataExtractor : public GenericInformationExtractor {
244 public:
245 SpamDataExtractor()
246 : GenericInformationExtractor( std::vector<StateNode>( spamNodes, spamNodes + numSpamNodes ) )
251 bool found() const {
252 return mResults.count( "x-spam-flag" ) &&
253 mResults.count( "spam-flag-yes" ) &&
254 mResults.count( "stop" ) ;
258 // to understand this table, study the output of
259 // libksieve/tests/parsertest
260 // 'if not address :domain :contains ["from"] ["mydomain.org"] { keep; stop; }'
261 static const GenericInformationExtractor::StateNode domainNodes[] = {
262 { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0
263 { 0, GIE::TestStart, "not", 2, 0, 0, }, // 1
264 { 0, GIE::TestStart, "address", 3, 0, 0 }, // 2
266 // :domain and :contains in arbitrary order:
267 { 0, GIE::TaggedArgument, "domain", 4, 5, 0 }, // 3
268 { 0, GIE::TaggedArgument, "contains", 7, 0, 0 }, // 4
269 { 0, GIE::TaggedArgument, "contains", 6, 0, 0 }, // 5
270 { 0, GIE::TaggedArgument, "domain", 7, 0, 0 }, // 6
272 // accept both string and string-list:
273 { 0, GIE::StringArgument, "from", 13, 8, "from" }, // 7
274 { 0, GIE::StringListArgumentStart, 0, 9, 0, 0 }, // 8
275 { 0, GIE::StringListEntry, "from", 10, 11, "from" }, // 9
276 { 0, GIE::StringListEntry, 0, 10, 12, 0 }, // 10
277 { 0, GIE::StringListArgumentEnd, 0, 0, 9, 0 }, // 11
278 { 0, GIE::StringListArgumentEnd, 0, 13, 0, 0 }, // 12
280 // string: save, string-list: save last
281 { 0, GIE::StringArgument, 0, 17, 14, "domainName" }, // 13
282 { 0, GIE::StringListArgumentStart, 0, 15, 0, 0 }, // 14
283 { 0, GIE::StringListEntry, 0, 15, 16, "domainName" }, // 15
284 { 0, GIE::StringListArgumentEnd, 0, 17, 0, 0 }, // 16
286 { 0, GIE::TestEnd, 0, 18, 0, 0 }, // 17
287 { 0, GIE::TestEnd, 0, 19, 0, 0 }, // 18
289 // block of commands, find "stop", take nested if's into account:
290 { 0, GIE::BlockStart, 0, 20, 0, 0 }, // 19
291 { 1, GIE::CommandStart, "stop", 23, 22, "stop" }, // 20
292 { -1, GIE::Any, 0, 20, 0, 0 }, // 21
293 { 0, GIE::BlockEnd, 0, 0, 21, 0 }, // 22
295 { -1, GIE::Any, 0, 23, 23, 0 } // 23 end state
297 static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ;
299 class DomainRestrictionDataExtractor : public GenericInformationExtractor {
300 public:
301 DomainRestrictionDataExtractor()
302 : GenericInformationExtractor( std::vector<StateNode>( domainNodes, domainNodes+numDomainNodes ) )
307 QString domainName() /*not const, since map::op[] isn't const*/ {
308 return mResults.count( "stop" ) && mResults.count( "from" )
309 ? mResults["domainName"] : QString();
313 class VacationDataExtractor : public KSieve::ScriptBuilder {
314 enum Context {
315 None = 0,
316 // command itself:
317 VacationCommand,
318 // tagged args:
319 Days, Addresses
321 public:
322 VacationDataExtractor()
323 : KSieve::ScriptBuilder(),
324 mContext( None ), mNotificationInterval( 0 )
326 kDebug(5006) <<"VacationDataExtractor instantiated";
328 virtual ~VacationDataExtractor() {}
330 int notificationInterval() const { return mNotificationInterval; }
331 const QString & messageText() const { return mMessageText; }
332 const QStringList & aliases() const { return mAliases; }
334 private:
335 void commandStart( const QString & identifier ) {
336 kDebug( 5006 ) <<"VacationDataExtractor::commandStart( \"" << identifier <<"\" )";
337 if ( identifier != "vacation" )
338 return;
339 reset();
340 mContext = VacationCommand;
343 void commandEnd() {
344 kDebug( 5006 ) <<"VacationDataExtractor::commandEnd()";
345 mContext = None;
348 void testStart( const QString & ) {}
349 void testEnd() {}
350 void testListStart() {}
351 void testListEnd() {}
352 void blockStart() {}
353 void blockEnd() {}
354 void hashComment( const QString & ) {}
355 void bracketComment( const QString & ) {}
356 void lineFeed() {}
357 void error( const KSieve::Error & e ) {
358 kDebug( 5006 ) <<"VacationDataExtractor::error() ###"
359 << e.asString() << "@" << e.line() << "," << e.column();
361 void finished() {}
363 void taggedArgument( const QString & tag ) {
364 kDebug( 5006 ) <<"VacationDataExtractor::taggedArgument( \"" << tag <<"\" )";
365 if ( mContext != VacationCommand )
366 return;
367 if ( tag == "days" )
368 mContext = Days;
369 else if ( tag == "addresses" )
370 mContext = Addresses;
373 void stringArgument( const QString & string, bool, const QString & ) {
374 kDebug( 5006 ) <<"VacationDataExtractor::stringArgument( \"" << string <<"\" )";
375 if ( mContext == Addresses ) {
376 mAliases.push_back( string );
377 mContext = VacationCommand;
378 } else if ( mContext == VacationCommand ) {
379 mMessageText = string;
380 mContext = VacationCommand;
384 void numberArgument( unsigned long number, char ) {
385 kDebug( 5006 ) <<"VacationDataExtractor::numberArgument( \"" << number <<"\" )";
386 if ( mContext != Days )
387 return;
388 if ( number > INT_MAX )
389 mNotificationInterval = INT_MAX;
390 else
391 mNotificationInterval = number;
392 mContext = VacationCommand;
395 void stringListArgumentStart() {}
396 void stringListEntry( const QString & string, bool, const QString & ) {
397 kDebug( 5006 ) <<"VacationDataExtractor::stringListEntry( \"" << string <<"\" )";
398 if ( mContext != Addresses )
399 return;
400 mAliases.push_back( string );
402 void stringListArgumentEnd() {
403 kDebug( 5006 ) <<"VacationDataExtractor::stringListArgumentEnd()";
404 if ( mContext != Addresses )
405 return;
406 mContext = VacationCommand;
409 private:
410 Context mContext;
411 int mNotificationInterval;
412 QString mMessageText;
413 QStringList mAliases;
415 void reset() {
416 kDebug(5006) <<"VacationDataExtractor::reset()";
417 mContext = None;
418 mNotificationInterval = 0;
419 mAliases.clear();
420 mMessageText.clear();
426 namespace KMail {
428 Vacation::Vacation( QObject * parent, const char * name )
429 : QObject( parent ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false )
431 setObjectName( name );
432 mUrl = findURL();
433 kDebug(5006) <<"Vacation: found url \"" << mUrl.prettyUrl() <<"\"";
434 if ( mUrl.isEmpty() ) // nothing to do...
435 return;
436 mSieveJob = SieveJob::get( mUrl );
437 connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)),
438 SLOT(slotGetResult(KMail::SieveJob*,bool,const QString&,bool)) );
441 Vacation::~Vacation() {
442 if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0;
443 delete mDialog; mDialog = 0;
444 kDebug(5006) <<"~Vacation()";
447 static inline QString dotstuff( QString s ) { // krazy:exclude=passbyvalue
448 if ( s.startsWith( '.' ) )
449 return '.' + s.replace( "\n.", "\n.." );
450 else
451 return s.replace( "\n.", "\n.." );
454 QString Vacation::composeScript( const QString & messageText,
455 int notificationInterval,
456 const AddrSpecList & addrSpecs,
457 bool sendForSpam, const QString & domain )
459 QString addressesArgument;
460 QStringList aliases;
461 if ( !addrSpecs.empty() ) {
462 addressesArgument += ":addresses [ ";
463 QStringList sl;
464 for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != addrSpecs.end() ; ++it ) {
465 sl.push_back( '"' + (*it).asString().replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"' );
466 aliases.push_back( (*it).asString() );
468 addressesArgument += sl.join( ", " ) + " ] ";
470 QString script = QString::fromLatin1("require \"vacation\";\n"
471 "\n"
472 "vacation ");
473 if ( !sendForSpam )
474 script += QString::fromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\""
475 " { keep; stop; }\n" ); // FIXME?
477 if ( !domain.isEmpty() ) // FIXME
478 script += QString::fromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).arg( domain );
480 script += "vacation ";
482 script += addressesArgument;
483 if ( notificationInterval > 0 )
484 script += QString::fromLatin1(":days %1 ").arg( notificationInterval );
485 script += QString::fromLatin1("text:\n");
486 script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText );
487 script += QString::fromLatin1( "\n.\n;\n" );
488 return script;
491 static KUrl findUrlForAccount( const KMail::ImapAccountBase * a ) {
492 assert( a );
493 const SieveConfig sieve = a->sieveConfig();
494 if ( !sieve.managesieveSupported() )
495 return KUrl();
496 if ( sieve.reuseConfig() ) {
497 // assemble Sieve url from the settings of the account:
498 KUrl u;
499 u.setProtocol( "sieve" );
500 u.setHost( a->host() );
501 u.setUser( a->login() );
502 u.setPass( a->passwd() );
503 u.setPort( sieve.port() );
504 u.setQuery( "x-mech=" + (a->auth() == "*" ? "PLAIN" : a->auth()) ); //translate IMAP LOGIN to PLAIN
505 u.setFileName( sieve.vacationFileName() );
506 return u;
507 } else {
508 KUrl u = sieve.alternateURL();
509 u.setFileName( sieve.vacationFileName() );
510 return u;
514 KUrl Vacation::findURL() const {
515 AccountManager * am = kmkernel->acctMgr();
516 assert( am );
517 for ( KMAccount * a = am->first() ; a ; a = am->next() )
518 if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) {
519 KUrl u = findUrlForAccount( iab );
520 if ( !u.isEmpty() )
521 return u;
523 return KUrl();
526 bool Vacation::parseScript( const QString & script, QString & messageText,
527 int & notificationInterval, QStringList & aliases,
528 bool & sendForSpam, QString & domainName ) {
529 if ( script.trimmed().isEmpty() ) {
530 messageText = defaultMessageText();
531 notificationInterval = defaultNotificationInterval();
532 aliases = defaultMailAliases();
533 sendForSpam = defaultSendForSpam();
534 domainName = defaultDomainName();
535 return true;
538 // The trimmed() call below prevents parsing errors. The
539 // slave somehow omits the last \n, which results in a lone \r at
540 // the end, leading to a parse error.
541 const QByteArray scriptUTF8 = script.trimmed().toUtf8();
542 kDebug(5006) <<"scriptUtf8 = \"" + scriptUTF8 +"\"";
543 KSieve::Parser parser( scriptUTF8.begin(),
544 scriptUTF8.begin() + scriptUTF8.length() );
545 VacationDataExtractor vdx;
546 SpamDataExtractor sdx;
547 DomainRestrictionDataExtractor drdx;
548 KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx );
549 parser.setScriptBuilder( &tsb );
550 if ( !parser.parse() )
551 return false;
552 messageText = vdx.messageText().trimmed();
553 notificationInterval = vdx.notificationInterval();
554 aliases = vdx.aliases();
555 if ( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ) {
556 sendForSpam = !sdx.found();
557 domainName = drdx.domainName();
559 return true;
562 QString Vacation::defaultMessageText() {
563 return i18n("I am out of office till %1.\n"
564 "\n"
565 "In urgent cases, please contact Mrs. <vacation replacement>\n"
566 "\n"
567 "email: <email address of vacation replacement>\n"
568 "phone: +49 711 1111 11\n"
569 "fax.: +49 711 1111 12\n"
570 "\n"
571 "Yours sincerely,\n"
572 "-- <enter your name and email address here>\n",
573 KGlobal::locale()->formatDate( QDate::currentDate().addDays( 1 ) ) );
576 int Vacation::defaultNotificationInterval() {
577 return 7; // days
580 QStringList Vacation::defaultMailAliases() {
581 QStringList sl;
582 for ( KPIMIdentities::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
583 it != kmkernel->identityManager()->end() ; ++it )
584 if ( !(*it).emailAddr().isEmpty() )
585 sl.push_back( (*it).emailAddr() );
586 return sl;
589 bool Vacation::defaultSendForSpam() {
590 return GlobalSettings::outOfOfficeReactToSpam();
593 QString Vacation::defaultDomainName() {
594 return GlobalSettings::outOfOfficeDomain();
597 void Vacation::slotGetResult( SieveJob * job, bool success,
598 const QString & script, bool active ) {
599 kDebug(5006) <<"Vacation::slotGetResult( ??," << success
600 << ", ?," << active << ")" << endl
601 << "script:" << endl
602 << script;
603 mSieveJob = 0; // job deletes itself after returning from this slot!
605 if ( mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() &&
606 !job->sieveCapabilities().contains("vacation") ) {
607 KMessageBox::sorry( 0, i18n("Your server did not list \"vacation\" in "
608 "its list of supported Sieve extensions;\n"
609 "without it, KMail cannot install out-of-"
610 "office replies for you.\n"
611 "Please contact you system administrator.") );
612 emit result( false );
613 return;
616 if ( !mDialog )
617 mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false );
619 QString messageText = defaultMessageText();
620 int notificationInterval = defaultNotificationInterval();
621 QStringList aliases = defaultMailAliases();
622 bool sendForSpam = defaultSendForSpam();
623 QString domainName = defaultDomainName();
624 if ( !success ) active = false; // default to inactive
626 if ( !success || !parseScript( script, messageText, notificationInterval, aliases, sendForSpam, domainName ) )
627 KMessageBox::information( 0, i18n("Someone (probably you) changed the "
628 "vacation script on the server.\n"
629 "KMail is no longer able to determine "
630 "the parameters for the autoreplies.\n"
631 "Default values will be used." ) );
633 mWasActive = active;
634 mDialog->setActivateVacation( active );
635 mDialog->setMessageText( messageText );
636 mDialog->setNotificationInterval( notificationInterval );
637 mDialog->setMailAliases( aliases.join(", ") );
638 mDialog->setSendForSpam( sendForSpam );
639 mDialog->setDomainName( domainName );
640 mDialog->enableDomainAndSendForSpam( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() );
642 connect( mDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) );
643 connect( mDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCancel()) );
644 connect( mDialog, SIGNAL(defaultClicked()), SLOT(slotDialogDefaults()) );
646 mDialog->show();
649 void Vacation::slotDialogDefaults() {
650 if ( !mDialog )
651 return;
652 mDialog->setActivateVacation( true );
653 mDialog->setMessageText( defaultMessageText() );
654 mDialog->setNotificationInterval( defaultNotificationInterval() );
655 mDialog->setMailAliases( defaultMailAliases().join(", ") );
656 mDialog->setSendForSpam( defaultSendForSpam() );
657 mDialog->setDomainName( defaultDomainName() );
660 void Vacation::slotDialogOk() {
661 kDebug(5006) <<"Vacation::slotDialogOk()";
662 // compose a new script:
663 const QString script = composeScript( mDialog->messageText(),
664 mDialog->notificationInterval(),
665 mDialog->mailAliases(),
666 mDialog->sendForSpam(),
667 mDialog->domainName() );
668 const bool active = mDialog->activateVacation();
670 kDebug(5006) <<"script:" << endl << script;
672 // and commit the dialog's settings to the server:
673 mSieveJob = SieveJob::put( mUrl, script, active, mWasActive );
674 connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)),
675 active
676 ? SLOT(slotPutActiveResult(KMail::SieveJob*,bool))
677 : SLOT(slotPutInactiveResult(KMail::SieveJob*,bool)) );
679 // destroy the dialog:
680 mDialog->delayedDestruct();
681 mDialog = 0;
684 void Vacation::slotDialogCancel() {
685 kDebug(5006) <<"Vacation::slotDialogCancel()";
686 mDialog->delayedDestruct();
687 mDialog = 0;
688 emit result( false );
691 void Vacation::slotPutActiveResult( SieveJob * job, bool success ) {
692 handlePutResult( job, success, true );
695 void Vacation::slotPutInactiveResult( SieveJob * job, bool success ) {
696 handlePutResult( job, success, false );
699 void Vacation::handlePutResult( SieveJob *, bool success, bool activated ) {
700 if ( success )
701 KMessageBox::information( 0, activated
702 ? i18n("Sieve script installed successfully on the server.\n"
703 "Out of Office reply is now active.")
704 : i18n("Sieve script installed successfully on the server.\n"
705 "Out of Office reply has been deactivated.") );
707 kDebug(5006) <<"Vacation::handlePutResult( ???," << success <<", ? )";
708 mSieveJob = 0; // job deletes itself after returning from this slot!
709 emit result( success );
713 } // namespace KMail
715 #include "vacation.moc"