kmail

vacation.cpp
1/*
2 vacation.cpp
3
4 KMail, the KDE mail client.
5 Copyright (c) 2002 Marc Mutz <mutz@kde.org>
6
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
13*/
14
15#ifdef HAVE_CONFIG_H
16#include <config.h>
17#endif
18
19#include "vacation.h"
20#include <limits.h>
21
22#include "vacationdialog.h"
23#include "sievejob.h"
24using KMail::SieveJob;
25#include "kmkernel.h"
26#include "kmmainwidget.h"
27#include "accountmanager.h"
29#include "kmacctimap.h"
30#include "kmmessage.h"
31#include "globalsettings.h"
32#include <libkpimidentities/identitymanager.h>
33#include <libkpimidentities/identity.h>
34
35#include <kmime_header_parsing.h>
36using KMime::Types::AddrSpecList;
37
38#include <ksieve/parser.h>
39#include <ksieve/scriptbuilder.h>
40#include <ksieve/error.h>
41
42#include <tdelocale.h>
43#include <tdemessagebox.h>
44#include <kdebug.h>
45
46#include <tqdatetime.h>
47
48#include <cassert>
49#include <vector>
50#include <map>
51#include <set>
52
53namespace KSieveExt {
54
55 class MultiScriptBuilder : public KSieve::ScriptBuilder {
56 std::vector<KSieve::ScriptBuilder*> mBuilders;
57 public:
58 MultiScriptBuilder() : KSieve::ScriptBuilder() {}
59 MultiScriptBuilder( KSieve::ScriptBuilder * sb1 )
60 : KSieve::ScriptBuilder(), mBuilders( 1 )
61 {
62 mBuilders[0] = sb1;
63 assert( sb1 );
64 }
65 MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
66 KSieve::ScriptBuilder * sb2 )
67 : KSieve::ScriptBuilder(), mBuilders( 2 )
68 {
69 mBuilders[0] = sb1;
70 mBuilders[1] = sb2;
71 assert( sb1 ); assert( sb2 );
72 }
73 MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
74 KSieve::ScriptBuilder * sb2,
75 KSieve::ScriptBuilder * sb3 )
76 : KSieve::ScriptBuilder(), mBuilders( 3 )
77 {
78 mBuilders[0] = sb1;
79 mBuilders[1] = sb2;
80 mBuilders[2] = sb3;
81 assert( sb1 ); assert( sb2 ); assert( sb3 );
82 }
83 ~MultiScriptBuilder() {}
84 private:
85#ifdef FOREACH
86#undef FOREACH
87#endif
88#define FOREACH for ( std::vector<KSieve::ScriptBuilder*>::const_iterator it = mBuilders.begin(), end = mBuilders.end() ; it != end ; ++it ) (*it)->
89 void commandStart( const TQString & identifier ) { FOREACH commandStart( identifier ); }
90 void commandEnd() { FOREACH commandEnd(); }
91 void testStart( const TQString & identifier ) { FOREACH testStart( identifier ); }
92 void testEnd() { FOREACH testEnd(); }
93 void testListStart() { FOREACH testListStart(); }
94 void testListEnd() { FOREACH testListEnd(); }
95 void blockStart() { FOREACH blockStart(); }
96 void blockEnd() { FOREACH blockEnd(); }
97 void hashComment( const TQString & comment ) { FOREACH hashComment( comment ); }
98 void bracketComment( const TQString & comment ) { FOREACH bracketComment( comment ); }
99 void lineFeed() { FOREACH lineFeed(); }
100 void error( const KSieve::Error & e ) { FOREACH error( e ); }
101 void finished() { FOREACH finished(); }
102 void taggedArgument( const TQString & tag ) { FOREACH taggedArgument( tag ); }
103 void stringArgument( const TQString & string, bool multiline, const TQString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); }
104 void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); }
105 void stringListArgumentStart() { FOREACH stringListArgumentStart(); }
106 void stringListEntry( const TQString & string, bool multiline, const TQString & fixme) { FOREACH stringListEntry( string, multiline, fixme ); }
107 void stringListArgumentEnd() { FOREACH stringListArgumentEnd(); }
108#undef FOREACH
109 };
110
111}
112
113namespace {
114
115 class GenericInformationExtractor : public KSieve::ScriptBuilder {
116 public:
117 enum BuilderMethod {
118 Any,
119 TaggedArgument,
120 StringArgument,
121 NumberArgument,
122 CommandStart,
123 CommandEnd,
124 TestStart,
125 TestEnd,
126 TestListStart,
127 TestListEnd,
128 BlockStart,
129 BlockEnd,
130 StringListArgumentStart,
131 StringListEntry,
132 StringListArgumentEnd
133 };
134
135 struct StateNode {
136 // expectation:
137 int depth;
138 BuilderMethod method;
139 const char * string;
140 // actions:
141 int if_found;
142 int if_not_found;
143 const char * save_tag;
144 };
145
146 const std::vector<StateNode> mNodes;
147 std::map<TQString,TQString> mResults;
148 std::set<unsigned int> mRecursionGuard;
149 unsigned int mState;
150 int mNestingDepth;
151
152 public:
153 GenericInformationExtractor( const std::vector<StateNode> & nodes )
154 : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ) {}
155
156 const std::map<TQString,TQString> & results() const { return mResults; }
157
158 private:
159 void process( BuilderMethod method, const TQString & string=TQString() ) {
160 doProcess( method, string );
161 mRecursionGuard.clear();
162 }
163 void doProcess( BuilderMethod method, const TQString & string ) {
164 mRecursionGuard.insert( mState );
165 bool found = true;
166 const StateNode & expected = mNodes[mState];
167 if ( expected.depth != -1 && mNestingDepth != expected.depth )
168 found = false;
169 if ( expected.method != Any && method != expected.method )
170 found = false;
171 if ( const char * str = expected.string )
172 if ( string.lower() != TQString::fromUtf8( str ).lower() )
173 found = false;
174 kdDebug(5006) << ( found ? "found: " : "not found: " )
175 << mState << " -> "
176 << ( found ? expected.if_found : expected.if_not_found ) << endl;
177 mState = found ? expected.if_found : expected.if_not_found ;
178 assert( mState < mNodes.size() );
179 if ( found )
180 if ( const char * save_tag = expected.save_tag )
181 mResults[save_tag] = string;
182 if ( !found && !mRecursionGuard.count( mState ) ) {
183 doProcess( method, string );
184 }
185 }
186 void commandStart( const TQString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( CommandStart, identifier ); }
187 void commandEnd() { kdDebug(5006) << k_funcinfo << endl; process( CommandEnd ); }
188 void testStart( const TQString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( TestStart, identifier ); }
189 void testEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestEnd ); }
190 void testListStart() { kdDebug(5006) << k_funcinfo << endl; process( TestListStart ); }
191 void testListEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestListEnd ); }
192 void blockStart() { kdDebug(5006) << k_funcinfo << endl; process( BlockStart ); ++mNestingDepth; }
193 void blockEnd() { kdDebug(5006) << k_funcinfo << endl; --mNestingDepth; process( BlockEnd ); }
194 void hashComment( const TQString & ) { kdDebug(5006) << k_funcinfo << endl; }
195 void bracketComment( const TQString & ) { kdDebug(5006) << k_funcinfo << endl; }
196 void lineFeed() { kdDebug(5006) << k_funcinfo << endl; }
197 void error( const KSieve::Error & ) {
198 kdDebug(5006) << k_funcinfo << endl;
199 mState = 0;
200 }
201 void finished() { kdDebug(5006) << k_funcinfo << endl; }
202
203 void taggedArgument( const TQString & tag ) { kdDebug(5006) << k_funcinfo << endl; process( TaggedArgument, tag ); }
204 void stringArgument( const TQString & string, bool, const TQString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringArgument, string ); }
205 void numberArgument( unsigned long number, char ) { kdDebug(5006) << k_funcinfo << endl; process( NumberArgument, TQString::number( number ) ); }
206 void stringListArgumentStart() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentStart ); }
207 void stringListEntry( const TQString & string, bool, const TQString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringListEntry, string ); }
208 void stringListArgumentEnd() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentEnd ); }
209 };
210
211 typedef GenericInformationExtractor GIE;
212 static const GenericInformationExtractor::StateNode spamNodes[] = {
213 { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0
214 { 0, GIE::TestStart, "header", 2, 0, 0 }, // 1
215 { 0, GIE::TaggedArgument, "contains", 3, 0, 0 }, // 2
216
217 // accept both string and string-list:
218 { 0, GIE::StringArgument, "x-spam-flag", 9, 4, "x-spam-flag" }, // 3
219 { 0, GIE::StringListArgumentStart, 0, 5, 0, 0 }, // 4
220 { 0, GIE::StringListEntry, "x-spam-flag", 6, 7, "x-spam-flag" }, // 5
221 { 0, GIE::StringListEntry, 0, 6, 8, 0 }, // 6
222 { 0, GIE::StringListArgumentEnd, 0, 0, 5, 0 }, // 7
223 { 0, GIE::StringListArgumentEnd, 0, 9, 0, 0 }, // 8
224
225 // accept both string and string-list:
226 { 0, GIE::StringArgument, "yes", 15, 10, "spam-flag-yes" }, // 9
227 { 0, GIE::StringListArgumentStart, 0, 11, 0, 0 }, // 10
228 { 0, GIE::StringListEntry, "yes", 12, 13, "spam-flag-yes" }, // 11
229 { 0, GIE::StringListEntry, 0, 12, 14, 0 }, // 12
230 { 0, GIE::StringListArgumentEnd, 0, 0, 11, 0 }, // 13
231 { 0, GIE::StringListArgumentEnd, 0, 15, 0, 0 }, // 14
232
233 { 0, GIE::TestEnd, 0, 16, 0, 0 }, // 15
234
235 // block of command, find "stop", take nested if's into account:
236 { 0, GIE::BlockStart, 0, 17, 0, 0 }, // 16
237 { 1, GIE::CommandStart, "stop", 20, 19, "stop" }, // 17
238 { -1, GIE::Any, 0, 17, 0, 0 }, // 18
239 { 0, GIE::BlockEnd, 0, 0, 18, 0 }, // 19
240
241 { -1, GIE::Any, 0, 20, 20, 0 }, // 20 end state
242 };
243 static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ;
244
245 class SpamDataExtractor : public GenericInformationExtractor {
246 public:
247 SpamDataExtractor()
248 : GenericInformationExtractor( std::vector<StateNode>( spamNodes, spamNodes + numSpamNodes ) )
249 {
250
251 }
252
253 bool found() const {
254 return mResults.count( "x-spam-flag" ) &&
255 mResults.count( "spam-flag-yes" ) &&
256 mResults.count( "stop" ) ;
257 }
258 };
259
260 // to understand this table, study the output of
261 // libksieve/tests/parsertest
262 // 'if not address :domain :contains ["from"] ["mydomain.org"] { keep; stop; }'
263 static const GenericInformationExtractor::StateNode domainNodes[] = {
264 { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0
265 { 0, GIE::TestStart, "not", 2, 0, 0, }, // 1
266 { 0, GIE::TestStart, "address", 3, 0, 0 }, // 2
267
268 // :domain and :contains in arbitrary order:
269 { 0, GIE::TaggedArgument, "domain", 4, 5, 0 }, // 3
270 { 0, GIE::TaggedArgument, "contains", 7, 0, 0 }, // 4
271 { 0, GIE::TaggedArgument, "contains", 6, 0, 0 }, // 5
272 { 0, GIE::TaggedArgument, "domain", 7, 0, 0 }, // 6
273
274 // accept both string and string-list:
275 { 0, GIE::StringArgument, "from", 13, 8, "from" }, // 7
276 { 0, GIE::StringListArgumentStart, 0, 9, 0, 0 }, // 8
277 { 0, GIE::StringListEntry, "from", 10, 11, "from" }, // 9
278 { 0, GIE::StringListEntry, 0, 10, 12, 0 }, // 10
279 { 0, GIE::StringListArgumentEnd, 0, 0, 9, 0 }, // 11
280 { 0, GIE::StringListArgumentEnd, 0, 13, 0, 0 }, // 12
281
282 // string: save, string-list: save last
283 { 0, GIE::StringArgument, 0, 17, 14, "domainName" }, // 13
284 { 0, GIE::StringListArgumentStart, 0, 15, 0, 0 }, // 14
285 { 0, GIE::StringListEntry, 0, 15, 16, "domainName" }, // 15
286 { 0, GIE::StringListArgumentEnd, 0, 17, 0, 0 }, // 16
287
288 { 0, GIE::TestEnd, 0, 18, 0, 0 }, // 17
289 { 0, GIE::TestEnd, 0, 19, 0, 0 }, // 18
290
291 // block of commands, find "stop", take nested if's into account:
292 { 0, GIE::BlockStart, 0, 20, 0, 0 }, // 19
293 { 1, GIE::CommandStart, "stop", 23, 22, "stop" }, // 20
294 { -1, GIE::Any, 0, 20, 0, 0 }, // 21
295 { 0, GIE::BlockEnd, 0, 0, 21, 0 }, // 22
296
297 { -1, GIE::Any, 0, 23, 23, 0 } // 23 end state
298 };
299 static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ;
300
301 class DomainRestrictionDataExtractor : public GenericInformationExtractor {
302 public:
303 DomainRestrictionDataExtractor()
304 : GenericInformationExtractor( std::vector<StateNode>( domainNodes, domainNodes+numDomainNodes ) )
305 {
306
307 }
308
309 TQString domainName() /*not const, since map::op[] isn't const*/ {
310 return mResults.count( "stop" ) && mResults.count( "from" )
311 ? mResults["domainName"] : TQString() ;
312 }
313 };
314
315 class VacationDataExtractor : public KSieve::ScriptBuilder {
316 enum Context {
317 None = 0,
318 // command itself:
319 VacationCommand,
320 // tagged args:
321 Days, Addresses
322 };
323 public:
324 VacationDataExtractor()
325 : KSieve::ScriptBuilder(),
326 mContext( None ), mNotificationInterval( 0 )
327 {
328 kdDebug(5006) << "VacationDataExtractor instantiated" << endl;
329 }
330 virtual ~VacationDataExtractor() {}
331
332 int notificationInterval() const { return mNotificationInterval; }
333 const TQString & messageText() const { return mMessageText; }
334 const TQStringList & aliases() const { return mAliases; }
335
336 private:
337 void commandStart( const TQString & identifier ) {
338 kdDebug( 5006 ) << "VacationDataExtractor::commandStart( \"" << identifier << "\" )" << endl;
339 if ( identifier != "vacation" )
340 return;
341 reset();
342 mContext = VacationCommand;
343 }
344
345 void commandEnd() {
346 kdDebug( 5006 ) << "VacationDataExtractor::commandEnd()" << endl;
347 mContext = None;
348 }
349
350 void testStart( const TQString & ) {}
351 void testEnd() {}
352 void testListStart() {}
353 void testListEnd() {}
354 void blockStart() {}
355 void blockEnd() {}
356 void hashComment( const TQString & ) {}
357 void bracketComment( const TQString & ) {}
358 void lineFeed() {}
359 void error( const KSieve::Error & e ) {
360 kdDebug( 5006 ) << "VacationDataExtractor::error() ### "
361 << e.asString() << " @ " << e.line() << "," << e.column()
362 << endl;
363 }
364 void finished() {}
365
366 void taggedArgument( const TQString & tag ) {
367 kdDebug( 5006 ) << "VacationDataExtractor::taggedArgument( \"" << tag << "\" )" << endl;
368 if ( mContext != VacationCommand )
369 return;
370 if ( tag == "days" )
371 mContext = Days;
372 else if ( tag == "addresses" )
373 mContext = Addresses;
374 }
375
376 void stringArgument( const TQString & string, bool, const TQString & ) {
377 kdDebug( 5006 ) << "VacationDataExtractor::stringArgument( \"" << string << "\" )" << endl;
378 if ( mContext == Addresses ) {
379 mAliases.push_back( string );
380 mContext = VacationCommand;
381 } else if ( mContext == VacationCommand ) {
382 mMessageText = string;
383 mContext = VacationCommand;
384 }
385 }
386
387 void numberArgument( unsigned long number, char ) {
388 kdDebug( 5006 ) << "VacationDataExtractor::numberArgument( \"" << number << "\" )" << endl;
389 if ( mContext != Days )
390 return;
391 if ( number > INT_MAX )
392 mNotificationInterval = INT_MAX;
393 else
394 mNotificationInterval = number;
395 mContext = VacationCommand;
396 }
397
398 void stringListArgumentStart() {}
399 void stringListEntry( const TQString & string, bool, const TQString & ) {
400 kdDebug( 5006 ) << "VacationDataExtractor::stringListEntry( \"" << string << "\" )" << endl;
401 if ( mContext != Addresses )
402 return;
403 mAliases.push_back( string );
404 }
405 void stringListArgumentEnd() {
406 kdDebug( 5006 ) << "VacationDataExtractor::stringListArgumentEnd()" << endl;
407 if ( mContext != Addresses )
408 return;
409 mContext = VacationCommand;
410 }
411
412 private:
413 Context mContext;
414 int mNotificationInterval;
415 TQString mMessageText;
416 TQStringList mAliases;
417
418 void reset() {
419 kdDebug(5006) << "VacationDataExtractor::reset()" << endl;
420 mContext = None;
421 mNotificationInterval = 0;
422 mAliases.clear();
423 mMessageText = TQString();
424 }
425 };
426
427}
428
429namespace KMail {
430
431 Vacation::Vacation( TQObject * parent, bool checkOnly, const char * name )
432 : TQObject( parent, name ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false ), mCheckOnly( checkOnly )
433 {
434 mUrl = findURL();
435 kdDebug(5006) << "Vacation: found url \"" << mUrl.prettyURL() << "\"" << endl;
436 if ( mUrl.isEmpty() ) // nothing to do...
437 return;
438 mSieveJob = SieveJob::get( mUrl, !checkOnly );
439 connect( mSieveJob, TQ_SIGNAL(gotScript(KMail::SieveJob*,bool,const TQString&,bool)),
440 TQ_SLOT(slotGetResult(KMail::SieveJob*,bool,const TQString&,bool)) );
441 }
442
443 Vacation::~Vacation() {
444 if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0;
445 delete mDialog; mDialog = 0;
446 kdDebug(5006) << "~Vacation()" << endl;
447 }
448
449 static inline TQString dotstuff( TQString s ) {
450 if ( s.startsWith( "." ) )
451 return '.' + s.replace( "\n.", "\n.." );
452 else
453 return s.replace( "\n.", "\n.." );
454 }
455
456 TQString Vacation::composeScript( const TQString & messageText,
457 int notificationInterval,
458 const AddrSpecList & addrSpecs,
459 bool sendForSpam, const TQString & domain )
460 {
461 TQString addressesArgument;
462 TQStringList aliases;
463 if ( !addrSpecs.empty() ) {
464 addressesArgument += ":addresses [ ";
465 TQStringList sl;
466 for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != addrSpecs.end() ; ++it ) {
467 sl.push_back( '"' + (*it).asString().replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"' );
468 aliases.push_back( (*it).asString() );
469 }
470 addressesArgument += sl.join( ", " ) + " ] ";
471 }
472 TQString script = TQString::fromLatin1("require \"vacation\";\n\n" );
473 if ( !sendForSpam )
474 script += TQString::fromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\""
475 " { keep; stop; }\n" ); // FIXME?
476
477 if ( !domain.isEmpty() ) // FIXME
478 script += TQString::fromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).arg( domain );
479
480 script += "vacation ";
481 script += addressesArgument;
482 if ( notificationInterval > 0 )
483 script += TQString::fromLatin1(":days %1 ").arg( notificationInterval );
484 script += TQString::fromLatin1("text:\n");
485 script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText );
486 script += TQString::fromLatin1( "\n.\n;\n" );
487 return script;
488 }
489
490 static KURL findUrlForAccount( const KMail::ImapAccountBase * a ) {
491 assert( a );
492 const SieveConfig sieve = a->sieveConfig();
493 if ( !sieve.managesieveSupported() )
494 return KURL();
495 if ( sieve.reuseConfig() ) {
496 // assemble Sieve url from the settings of the account:
497 KURL u;
498 u.setProtocol( "sieve" );
499 u.setHost( a->host() );
500 u.setUser( a->login() );
501 u.setPass( a->passwd() );
502 u.setPort( sieve.port() );
503 u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() ); //translate IMAP LOGIN to PLAIN
504 if ( !a->useSSL() && !a->useTLS() )
505 u.addQueryItem( "x-allow-unencrypted", "true" );
506 u.setFileName( sieve.vacationFileName() );
507 return u;
508 } else {
509 KURL u = sieve.alternateURL();
510 if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
511 u.addQueryItem( "x-allow-unencrypted", "true" );
512 u.setFileName( sieve.vacationFileName() );
513 return u;
514 }
515 }
516
517 KURL Vacation::findURL() const {
518 AccountManager * am = kmkernel->acctMgr();
519 assert( am );
520 for ( KMAccount * a = am->first() ; a ; a = am->next() )
521 if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) {
522 KURL u = findUrlForAccount( iab );
523 if ( !u.isEmpty() )
524 return u;
525 }
526 return KURL();
527 }
528
529 bool Vacation::parseScript( const TQString & script, TQString & messageText,
530 int & notificationInterval, TQStringList & aliases,
531 bool & sendForSpam, TQString & domainName ) {
532 if ( script.stripWhiteSpace().isEmpty() ) {
533 messageText = defaultMessageText();
534 notificationInterval = defaultNotificationInterval();
535 aliases = defaultMailAliases();
536 sendForSpam = defaultSendForSpam();
537 domainName = defaultDomainName();
538 return true;
539 }
540
541 // The stripWhiteSpace() call below prevents parsing errors. The
542 // slave somehow omits the last \n, which results in a lone \r at
543 // the end, leading to a parse error.
544 const TQCString scriptUTF8 = script.stripWhiteSpace().utf8();
545 kdDebug(5006) << "scriptUtf8 = \"" + scriptUTF8 + "\"" << endl;
546 KSieve::Parser parser( scriptUTF8.begin(),
547 scriptUTF8.begin() + scriptUTF8.length() );
548 VacationDataExtractor vdx;
549 SpamDataExtractor sdx;
550 DomainRestrictionDataExtractor drdx;
551 KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx );
552 parser.setScriptBuilder( &tsb );
553 if ( !parser.parse() )
554 return false;
555 messageText = vdx.messageText().stripWhiteSpace();
556 notificationInterval = vdx.notificationInterval();
557 aliases = vdx.aliases();
558 if ( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ) {
559 sendForSpam = !sdx.found();
560 domainName = drdx.domainName();
561 }
562 return true;
563 }
564
565 TQString Vacation::defaultMessageText() {
566 return i18n("I am out of office till %1.\n"
567 "\n"
568 "In urgent cases, please contact Mrs. <vacation replacement>\n"
569 "\n"
570 "email: <email address of vacation replacement>\n"
571 "phone: +49 711 1111 11\n"
572 "fax.: +49 711 1111 12\n"
573 "\n"
574 "Yours sincerely,\n"
575 "-- <enter your name and email address here>\n")
576 .arg( TDEGlobal::locale()->formatDate( TQDate::currentDate().addDays( 1 ) ) );
577 }
578
579 int Vacation::defaultNotificationInterval() {
580 return 7; // days
581 }
582
583 TQStringList Vacation::defaultMailAliases() {
584 TQStringList sl;
585 for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
586 it != kmkernel->identityManager()->end() ; ++it ) {
587 if ( !(*it).primaryEmailAddress().isEmpty() )
588 sl.push_back( (*it).primaryEmailAddress() );
589 sl += (*it).emailAliases();
590 }
591 return sl;
592 }
593
594 bool Vacation::defaultSendForSpam() {
595 return GlobalSettings::outOfOfficeReactToSpam();
596 }
597
598 TQString Vacation::defaultDomainName() {
599 return GlobalSettings::outOfOfficeDomain();
600 }
601
602 void Vacation::slotGetResult( SieveJob * job, bool success,
603 const TQString & script, bool active ) {
604 kdDebug(5006) << "Vacation::slotGetResult( ??, " << success
605 << ", ?, " << active << " )" << endl
606 << "script:" << endl
607 << script << endl;
608 mSieveJob = 0; // job deletes itself after returning from this slot!
609
610 if ( !mCheckOnly && mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() &&
611 !job->sieveCapabilities().contains("vacation") ) {
612 KMessageBox::sorry( 0, i18n("Your server did not list \"vacation\" in "
613 "its list of supported Sieve extensions;\n"
614 "without it, KMail cannot install out-of-"
615 "office replies for you.\n"
616 "Please contact you system administrator.") );
617 emit result( false );
618 return;
619 }
620
621 if ( !mDialog && !mCheckOnly )
622 mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false );
623
624 TQString messageText = defaultMessageText();
625 int notificationInterval = defaultNotificationInterval();
626 TQStringList aliases = defaultMailAliases();
627 bool sendForSpam = defaultSendForSpam();
628 TQString domainName = defaultDomainName();
629 if ( !success ) active = false; // default to inactive
630
631 if ( !mCheckOnly && ( !success || !parseScript( script, messageText, notificationInterval, aliases, sendForSpam, domainName ) ) )
632 KMessageBox::information( 0, i18n("Someone (probably you) changed the "
633 "vacation script on the server.\n"
634 "KMail is no longer able to determine "
635 "the parameters for the autoreplies.\n"
636 "Default values will be used." ) );
637
638 mWasActive = active;
639 if ( mDialog ) {
640 mDialog->setActivateVacation( active );
641 mDialog->setMessageText( messageText );
642 mDialog->setNotificationInterval( notificationInterval );
643 mDialog->setMailAliases( aliases.join(", ") );
644 mDialog->setSendForSpam( sendForSpam );
645 mDialog->setDomainName( domainName );
646 mDialog->enableDomainAndSendForSpam( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() );
647
648 connect( mDialog, TQ_SIGNAL(okClicked()), TQ_SLOT(slotDialogOk()) );
649 connect( mDialog, TQ_SIGNAL(cancelClicked()), TQ_SLOT(slotDialogCancel()) );
650 connect( mDialog, TQ_SIGNAL(defaultClicked()), TQ_SLOT(slotDialogDefaults()) );
651
652 mDialog->show();
653 }
654
655 emit scriptActive( mWasActive );
656 if ( mCheckOnly && mWasActive ) {
657 if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n"
658 "Do you want to edit it?"), i18n("Out-of-office reply still active"),
659 KGuiItem( i18n( "Edit"), "edit" ), KGuiItem( i18n("Ignore"), "button_cancel" ) )
660 == KMessageBox::Yes ) {
661 kmkernel->getKMMainWidget()->slotEditVacation();
662 }
663 }
664 }
665
666 void Vacation::slotDialogDefaults() {
667 if ( !mDialog )
668 return;
669 mDialog->setActivateVacation( true );
670 mDialog->setMessageText( defaultMessageText() );
671 mDialog->setNotificationInterval( defaultNotificationInterval() );
672 mDialog->setMailAliases( defaultMailAliases().join(", ") );
673 mDialog->setSendForSpam( defaultSendForSpam() );
674 mDialog->setDomainName( defaultDomainName() );
675 mDialog->setDomainCheck( false );
676 }
677
678 void Vacation::slotDialogOk() {
679 kdDebug(5006) << "Vacation::slotDialogOk()" << endl;
680 // compose a new script:
681 const TQString script = composeScript( mDialog->messageText(),
682 mDialog->notificationInterval(),
683 mDialog->mailAliases(),
684 mDialog->sendForSpam(),
685 mDialog->domainName() );
686 const bool active = mDialog->activateVacation();
687 emit scriptActive( active );
688
689 kdDebug(5006) << "script:" << endl << script << endl;
690
691 // and commit the dialog's settings to the server:
692 mSieveJob = SieveJob::put( mUrl, script, active, mWasActive );
693 connect( mSieveJob, TQ_SIGNAL(gotScript(KMail::SieveJob*,bool,const TQString&,bool)),
694 active
695 ? TQ_SLOT(slotPutActiveResult(KMail::SieveJob*,bool))
696 : TQ_SLOT(slotPutInactiveResult(KMail::SieveJob*,bool)) );
697
698 // destroy the dialog:
699 mDialog->delayedDestruct();
700 mDialog = 0;
701 }
702
703 void Vacation::slotDialogCancel() {
704 kdDebug(5006) << "Vacation::slotDialogCancel()" << endl;
705 mDialog->delayedDestruct();
706 mDialog = 0;
707 emit result( false );
708 }
709
710 void Vacation::slotPutActiveResult( SieveJob * job, bool success ) {
711 handlePutResult( job, success, true );
712 }
713
714 void Vacation::slotPutInactiveResult( SieveJob * job, bool success ) {
715 handlePutResult( job, success, false );
716 }
717
718 void Vacation::handlePutResult( SieveJob *, bool success, bool activated ) {
719 if ( success )
720 KMessageBox::information( 0, activated
721 ? i18n("Sieve script installed successfully on the server.\n"
722 "Out of Office reply is now active.")
723 : i18n("Sieve script installed successfully on the server.\n"
724 "Out of Office reply has been deactivated.") );
725
726 kdDebug(5006) << "Vacation::handlePutResult( ???, " << success << ", ? )"
727 << endl;
728 mSieveJob = 0; // job deletes itself after returning from this slot!
729 emit result( success );
730 emit scriptActive( activated );
731 }
732
733
734} // namespace KMail
735
736#include "vacation.moc"
The account manager is responsible for creating accounts of various types via the factory method crea...
const KMAccount * next() const
Next account of the list.
const KMAccount * first() const
First account of the list.
folderdiaquotatab.h
Definition: aboutdata.cpp:40