00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifdef HAVE_CONFIG_H
00016 #include <config.h>
00017 #endif
00018
00019 #include "vacation.h"
00020 #include <limits.h>
00021
00022 #include "vacationdialog.h"
00023 #include "sievejob.h"
00024 using KMail::SieveJob;
00025 #include "kmkernel.h"
00026 #include "kmmainwidget.h"
00027 #include "accountmanager.h"
00028 using KMail::AccountManager;
00029 #include "kmacctimap.h"
00030 #include "kmmessage.h"
00031 #include "globalsettings.h"
00032 #include <libkpimidentities/identitymanager.h>
00033 #include <libkpimidentities/identity.h>
00034
00035 #include <kmime_header_parsing.h>
00036 using KMime::Types::AddrSpecList;
00037
00038 #include <ksieve/parser.h>
00039 #include <ksieve/scriptbuilder.h>
00040 #include <ksieve/error.h>
00041
00042 #include <klocale.h>
00043 #include <kmessagebox.h>
00044 #include <kdebug.h>
00045
00046 #include <qdatetime.h>
00047
00048 #include <cassert>
00049 #include <vector>
00050 #include <map>
00051 #include <set>
00052
00053 namespace KSieveExt {
00054
00055 class MultiScriptBuilder : public KSieve::ScriptBuilder {
00056 std::vector<KSieve::ScriptBuilder*> mBuilders;
00057 public:
00058 MultiScriptBuilder() : KSieve::ScriptBuilder() {}
00059 MultiScriptBuilder( KSieve::ScriptBuilder * sb1 )
00060 : KSieve::ScriptBuilder(), mBuilders( 1 )
00061 {
00062 mBuilders[0] = sb1;
00063 assert( sb1 );
00064 }
00065 MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
00066 KSieve::ScriptBuilder * sb2 )
00067 : KSieve::ScriptBuilder(), mBuilders( 2 )
00068 {
00069 mBuilders[0] = sb1;
00070 mBuilders[1] = sb2;
00071 assert( sb1 ); assert( sb2 );
00072 }
00073 MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
00074 KSieve::ScriptBuilder * sb2,
00075 KSieve::ScriptBuilder * sb3 )
00076 : KSieve::ScriptBuilder(), mBuilders( 3 )
00077 {
00078 mBuilders[0] = sb1;
00079 mBuilders[1] = sb2;
00080 mBuilders[2] = sb3;
00081 assert( sb1 ); assert( sb2 ); assert( sb3 );
00082 }
00083 ~MultiScriptBuilder() {}
00084 private:
00085 #ifdef FOREACH
00086 #undef FOREACH
00087 #endif
00088 #define FOREACH for ( std::vector<KSieve::ScriptBuilder*>::const_iterator it = mBuilders.begin(), end = mBuilders.end() ; it != end ; ++it ) (*it)->
00089 void commandStart( const QString & identifier ) { FOREACH commandStart( identifier ); }
00090 void commandEnd() { FOREACH commandEnd(); }
00091 void testStart( const QString & identifier ) { FOREACH testStart( identifier ); }
00092 void testEnd() { FOREACH testEnd(); }
00093 void testListStart() { FOREACH testListStart(); }
00094 void testListEnd() { FOREACH testListEnd(); }
00095 void blockStart() { FOREACH blockStart(); }
00096 void blockEnd() { FOREACH blockEnd(); }
00097 void hashComment( const QString & comment ) { FOREACH hashComment( comment ); }
00098 void bracketComment( const QString & comment ) { FOREACH bracketComment( comment ); }
00099 void lineFeed() { FOREACH lineFeed(); }
00100 void error( const KSieve::Error & e ) { FOREACH error( e ); }
00101 void finished() { FOREACH finished(); }
00102 void taggedArgument( const QString & tag ) { FOREACH taggedArgument( tag ); }
00103 void stringArgument( const QString & string, bool multiline, const QString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); }
00104 void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); }
00105 void stringListArgumentStart() { FOREACH stringListArgumentStart(); }
00106 void stringListEntry( const QString & string, bool multiline, const QString & fixme) { FOREACH stringListEntry( string, multiline, fixme ); }
00107 void stringListArgumentEnd() { FOREACH stringListArgumentEnd(); }
00108 #undef FOREACH
00109 };
00110
00111 }
00112
00113 namespace {
00114
00115 class GenericInformationExtractor : public KSieve::ScriptBuilder {
00116 public:
00117 enum BuilderMethod {
00118 Any,
00119 TaggedArgument,
00120 StringArgument,
00121 NumberArgument,
00122 CommandStart,
00123 CommandEnd,
00124 TestStart,
00125 TestEnd,
00126 TestListStart,
00127 TestListEnd,
00128 BlockStart,
00129 BlockEnd,
00130 StringListArgumentStart,
00131 StringListEntry,
00132 StringListArgumentEnd
00133 };
00134
00135 struct StateNode {
00136
00137 int depth;
00138 BuilderMethod method;
00139 const char * string;
00140
00141 int if_found;
00142 int if_not_found;
00143 const char * save_tag;
00144 };
00145
00146 const std::vector<StateNode> mNodes;
00147 std::map<QString,QString> mResults;
00148 std::set<unsigned int> mRecursionGuard;
00149 unsigned int mState;
00150 int mNestingDepth;
00151
00152 public:
00153 GenericInformationExtractor( const std::vector<StateNode> & nodes )
00154 : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ) {}
00155
00156 const std::map<QString,QString> & results() const { return mResults; }
00157
00158 private:
00159 void process( BuilderMethod method, const QString & string=QString::null ) {
00160 doProcess( method, string );
00161 mRecursionGuard.clear();
00162 }
00163 void doProcess( BuilderMethod method, const QString & string ) {
00164 mRecursionGuard.insert( mState );
00165 bool found = true;
00166 const StateNode & expected = mNodes[mState];
00167 if ( expected.depth != -1 && mNestingDepth != expected.depth )
00168 found = false;
00169 if ( expected.method != Any && method != expected.method )
00170 found = false;
00171 if ( const char * str = expected.string )
00172 if ( string.lower() != QString::fromUtf8( str ).lower() )
00173 found = false;
00174 kdDebug(5006) << ( found ? "found: " : "not found: " )
00175 << mState << " -> "
00176 << ( found ? expected.if_found : expected.if_not_found ) << endl;
00177 mState = found ? expected.if_found : expected.if_not_found ;
00178 assert( mState < mNodes.size() );
00179 if ( found )
00180 if ( const char * save_tag = expected.save_tag )
00181 mResults[save_tag] = string;
00182 if ( !found && !mRecursionGuard.count( mState ) ) {
00183 doProcess( method, string );
00184 }
00185 }
00186 void commandStart( const QString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( CommandStart, identifier ); }
00187 void commandEnd() { kdDebug(5006) << k_funcinfo << endl; process( CommandEnd ); }
00188 void testStart( const QString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( TestStart, identifier ); }
00189 void testEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestEnd ); }
00190 void testListStart() { kdDebug(5006) << k_funcinfo << endl; process( TestListStart ); }
00191 void testListEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestListEnd ); }
00192 void blockStart() { kdDebug(5006) << k_funcinfo << endl; process( BlockStart ); ++mNestingDepth; }
00193 void blockEnd() { kdDebug(5006) << k_funcinfo << endl; --mNestingDepth; process( BlockEnd ); }
00194 void hashComment( const QString & ) { kdDebug(5006) << k_funcinfo << endl; }
00195 void bracketComment( const QString & ) { kdDebug(5006) << k_funcinfo << endl; }
00196 void lineFeed() { kdDebug(5006) << k_funcinfo << endl; }
00197 void error( const KSieve::Error & ) {
00198 kdDebug(5006) << k_funcinfo << endl;
00199 mState = 0;
00200 }
00201 void finished() { kdDebug(5006) << k_funcinfo << endl; }
00202
00203 void taggedArgument( const QString & tag ) { kdDebug(5006) << k_funcinfo << endl; process( TaggedArgument, tag ); }
00204 void stringArgument( const QString & string, bool, const QString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringArgument, string ); }
00205 void numberArgument( unsigned long number, char ) { kdDebug(5006) << k_funcinfo << endl; process( NumberArgument, QString::number( number ) ); }
00206 void stringListArgumentStart() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentStart ); }
00207 void stringListEntry( const QString & string, bool, const QString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringListEntry, string ); }
00208 void stringListArgumentEnd() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentEnd ); }
00209 };
00210
00211 typedef GenericInformationExtractor GIE;
00212 static const GenericInformationExtractor::StateNode spamNodes[] = {
00213 { 0, GIE::CommandStart, "if", 1, 0, 0 },
00214 { 0, GIE::TestStart, "header", 2, 0, 0 },
00215 { 0, GIE::TaggedArgument, "contains", 3, 0, 0 },
00216
00217
00218 { 0, GIE::StringArgument, "x-spam-flag", 9, 4, "x-spam-flag" },
00219 { 0, GIE::StringListArgumentStart, 0, 5, 0, 0 },
00220 { 0, GIE::StringListEntry, "x-spam-flag", 6, 7, "x-spam-flag" },
00221 { 0, GIE::StringListEntry, 0, 6, 8, 0 },
00222 { 0, GIE::StringListArgumentEnd, 0, 0, 5, 0 },
00223 { 0, GIE::StringListArgumentEnd, 0, 9, 0, 0 },
00224
00225
00226 { 0, GIE::StringArgument, "yes", 15, 10, "spam-flag-yes" },
00227 { 0, GIE::StringListArgumentStart, 0, 11, 0, 0 },
00228 { 0, GIE::StringListEntry, "yes", 12, 13, "spam-flag-yes" },
00229 { 0, GIE::StringListEntry, 0, 12, 14, 0 },
00230 { 0, GIE::StringListArgumentEnd, 0, 0, 11, 0 },
00231 { 0, GIE::StringListArgumentEnd, 0, 15, 0, 0 },
00232
00233 { 0, GIE::TestEnd, 0, 16, 0, 0 },
00234
00235
00236 { 0, GIE::BlockStart, 0, 17, 0, 0 },
00237 { 1, GIE::CommandStart, "stop", 20, 19, "stop" },
00238 { -1, GIE::Any, 0, 17, 0, 0 },
00239 { 0, GIE::BlockEnd, 0, 0, 18, 0 },
00240
00241 { -1, GIE::Any, 0, 20, 20, 0 },
00242 };
00243 static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ;
00244
00245 class SpamDataExtractor : public GenericInformationExtractor {
00246 public:
00247 SpamDataExtractor()
00248 : GenericInformationExtractor( std::vector<StateNode>( spamNodes, spamNodes + numSpamNodes ) )
00249 {
00250
00251 }
00252
00253 bool found() const {
00254 return mResults.count( "x-spam-flag" ) &&
00255 mResults.count( "spam-flag-yes" ) &&
00256 mResults.count( "stop" ) ;
00257 }
00258 };
00259
00260
00261
00262
00263 static const GenericInformationExtractor::StateNode domainNodes[] = {
00264 { 0, GIE::CommandStart, "if", 1, 0, 0 },
00265 { 0, GIE::TestStart, "not", 2, 0, 0, },
00266 { 0, GIE::TestStart, "address", 3, 0, 0 },
00267
00268
00269 { 0, GIE::TaggedArgument, "domain", 4, 5, 0 },
00270 { 0, GIE::TaggedArgument, "contains", 7, 0, 0 },
00271 { 0, GIE::TaggedArgument, "contains", 6, 0, 0 },
00272 { 0, GIE::TaggedArgument, "domain", 7, 0, 0 },
00273
00274
00275 { 0, GIE::StringArgument, "from", 13, 8, "from" },
00276 { 0, GIE::StringListArgumentStart, 0, 9, 0, 0 },
00277 { 0, GIE::StringListEntry, "from", 10, 11, "from" },
00278 { 0, GIE::StringListEntry, 0, 10, 12, 0 },
00279 { 0, GIE::StringListArgumentEnd, 0, 0, 9, 0 },
00280 { 0, GIE::StringListArgumentEnd, 0, 13, 0, 0 },
00281
00282
00283 { 0, GIE::StringArgument, 0, 17, 14, "domainName" },
00284 { 0, GIE::StringListArgumentStart, 0, 15, 0, 0 },
00285 { 0, GIE::StringListEntry, 0, 15, 16, "domainName" },
00286 { 0, GIE::StringListArgumentEnd, 0, 17, 0, 0 },
00287
00288 { 0, GIE::TestEnd, 0, 18, 0, 0 },
00289 { 0, GIE::TestEnd, 0, 19, 0, 0 },
00290
00291
00292 { 0, GIE::BlockStart, 0, 20, 0, 0 },
00293 { 1, GIE::CommandStart, "stop", 23, 22, "stop" },
00294 { -1, GIE::Any, 0, 20, 0, 0 },
00295 { 0, GIE::BlockEnd, 0, 0, 21, 0 },
00296
00297 { -1, GIE::Any, 0, 23, 23, 0 }
00298 };
00299 static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ;
00300
00301 class DomainRestrictionDataExtractor : public GenericInformationExtractor {
00302 public:
00303 DomainRestrictionDataExtractor()
00304 : GenericInformationExtractor( std::vector<StateNode>( domainNodes, domainNodes+numDomainNodes ) )
00305 {
00306
00307 }
00308
00309 QString domainName() {
00310 return mResults.count( "stop" ) && mResults.count( "from" )
00311 ? mResults["domainName"] : QString::null ;
00312 }
00313 };
00314
00315 class VacationDataExtractor : public KSieve::ScriptBuilder {
00316 enum Context {
00317 None = 0,
00318
00319 VacationCommand,
00320
00321 Days, Addresses
00322 };
00323 public:
00324 VacationDataExtractor()
00325 : KSieve::ScriptBuilder(),
00326 mContext( None ), mNotificationInterval( 0 )
00327 {
00328 kdDebug(5006) << "VacationDataExtractor instantiated" << endl;
00329 }
00330 virtual ~VacationDataExtractor() {}
00331
00332 int notificationInterval() const { return mNotificationInterval; }
00333 const QString & messageText() const { return mMessageText; }
00334 const QStringList & aliases() const { return mAliases; }
00335
00336 private:
00337 void commandStart( const QString & identifier ) {
00338 kdDebug( 5006 ) << "VacationDataExtractor::commandStart( \"" << identifier << "\" )" << endl;
00339 if ( identifier != "vacation" )
00340 return;
00341 reset();
00342 mContext = VacationCommand;
00343 }
00344
00345 void commandEnd() {
00346 kdDebug( 5006 ) << "VacationDataExtractor::commandEnd()" << endl;
00347 mContext = None;
00348 }
00349
00350 void testStart( const QString & ) {}
00351 void testEnd() {}
00352 void testListStart() {}
00353 void testListEnd() {}
00354 void blockStart() {}
00355 void blockEnd() {}
00356 void hashComment( const QString & ) {}
00357 void bracketComment( const QString & ) {}
00358 void lineFeed() {}
00359 void error( const KSieve::Error & e ) {
00360 kdDebug( 5006 ) << "VacationDataExtractor::error() ### "
00361 << e.asString() << " @ " << e.line() << "," << e.column()
00362 << endl;
00363 }
00364 void finished() {}
00365
00366 void taggedArgument( const QString & tag ) {
00367 kdDebug( 5006 ) << "VacationDataExtractor::taggedArgument( \"" << tag << "\" )" << endl;
00368 if ( mContext != VacationCommand )
00369 return;
00370 if ( tag == "days" )
00371 mContext = Days;
00372 else if ( tag == "addresses" )
00373 mContext = Addresses;
00374 }
00375
00376 void stringArgument( const QString & string, bool, const QString & ) {
00377 kdDebug( 5006 ) << "VacationDataExtractor::stringArgument( \"" << string << "\" )" << endl;
00378 if ( mContext == Addresses ) {
00379 mAliases.push_back( string );
00380 mContext = VacationCommand;
00381 } else if ( mContext == VacationCommand ) {
00382 mMessageText = string;
00383 mContext = VacationCommand;
00384 }
00385 }
00386
00387 void numberArgument( unsigned long number, char ) {
00388 kdDebug( 5006 ) << "VacationDataExtractor::numberArgument( \"" << number << "\" )" << endl;
00389 if ( mContext != Days )
00390 return;
00391 if ( number > INT_MAX )
00392 mNotificationInterval = INT_MAX;
00393 else
00394 mNotificationInterval = number;
00395 mContext = VacationCommand;
00396 }
00397
00398 void stringListArgumentStart() {}
00399 void stringListEntry( const QString & string, bool, const QString & ) {
00400 kdDebug( 5006 ) << "VacationDataExtractor::stringListEntry( \"" << string << "\" )" << endl;
00401 if ( mContext != Addresses )
00402 return;
00403 mAliases.push_back( string );
00404 }
00405 void stringListArgumentEnd() {
00406 kdDebug( 5006 ) << "VacationDataExtractor::stringListArgumentEnd()" << endl;
00407 if ( mContext != Addresses )
00408 return;
00409 mContext = VacationCommand;
00410 }
00411
00412 private:
00413 Context mContext;
00414 int mNotificationInterval;
00415 QString mMessageText;
00416 QStringList mAliases;
00417
00418 void reset() {
00419 kdDebug(5006) << "VacationDataExtractor::reset()" << endl;
00420 mContext = None;
00421 mNotificationInterval = 0;
00422 mAliases.clear();
00423 mMessageText = QString::null;
00424 }
00425 };
00426
00427 }
00428
00429 namespace KMail {
00430
00431 Vacation::Vacation( QObject * parent, bool checkOnly, const char * name )
00432 : QObject( parent, name ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false ), mCheckOnly( checkOnly )
00433 {
00434 mUrl = findURL();
00435 kdDebug(5006) << "Vacation: found url \"" << mUrl.prettyURL() << "\"" << endl;
00436 if ( mUrl.isEmpty() )
00437 return;
00438 mSieveJob = SieveJob::get( mUrl, !checkOnly );
00439 connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)),
00440 SLOT(slotGetResult(KMail::SieveJob*,bool,const QString&,bool)) );
00441 }
00442
00443 Vacation::~Vacation() {
00444 if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0;
00445 delete mDialog; mDialog = 0;
00446 kdDebug(5006) << "~Vacation()" << endl;
00447 }
00448
00449 static inline QString dotstuff( QString s ) {
00450 if ( s.startsWith( "." ) )
00451 return '.' + s.replace( "\n.", "\n.." );
00452 else
00453 return s.replace( "\n.", "\n.." );
00454 }
00455
00456 QString Vacation::composeScript( const QString & messageText,
00457 int notificationInterval,
00458 const AddrSpecList & addrSpecs,
00459 bool sendForSpam, const QString & domain )
00460 {
00461 QString addressesArgument;
00462 QStringList aliases;
00463 if ( !addrSpecs.empty() ) {
00464 addressesArgument += ":addresses [ ";
00465 QStringList sl;
00466 for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != addrSpecs.end() ; ++it ) {
00467 sl.push_back( '"' + (*it).asString().replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"' );
00468 aliases.push_back( (*it).asString() );
00469 }
00470 addressesArgument += sl.join( ", " ) + " ] ";
00471 }
00472 QString script = QString::fromLatin1("require \"vacation\";\n\n" );
00473 if ( !sendForSpam )
00474 script += QString::fromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\""
00475 " { keep; stop; }\n" );
00476
00477 if ( !domain.isEmpty() )
00478 script += QString::fromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).arg( domain );
00479
00480 script += "vacation ";
00481 script += addressesArgument;
00482 if ( notificationInterval > 0 )
00483 script += QString::fromLatin1(":days %1 ").arg( notificationInterval );
00484 script += QString::fromLatin1("text:\n");
00485 script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText );
00486 script += QString::fromLatin1( "\n.\n;\n" );
00487 return script;
00488 }
00489
00490 static KURL findUrlForAccount( const KMail::ImapAccountBase * a ) {
00491 assert( a );
00492 const SieveConfig sieve = a->sieveConfig();
00493 if ( !sieve.managesieveSupported() )
00494 return KURL();
00495 if ( sieve.reuseConfig() ) {
00496
00497 KURL u;
00498 u.setProtocol( "sieve" );
00499 u.setHost( a->host() );
00500 u.setUser( a->login() );
00501 u.setPass( a->passwd() );
00502 u.setPort( sieve.port() );
00503 u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() );
00504 if ( !a->useSSL() && !a->useTLS() )
00505 u.addQueryItem( "x-allow-unencrypted", "true" );
00506 u.setFileName( sieve.vacationFileName() );
00507 return u;
00508 } else {
00509 KURL u = sieve.alternateURL();
00510 if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
00511 u.addQueryItem( "x-allow-unencrypted", "true" );
00512 u.setFileName( sieve.vacationFileName() );
00513 return u;
00514 }
00515 }
00516
00517 KURL Vacation::findURL() const {
00518 AccountManager * am = kmkernel->acctMgr();
00519 assert( am );
00520 for ( KMAccount * a = am->first() ; a ; a = am->next() )
00521 if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) {
00522 KURL u = findUrlForAccount( iab );
00523 if ( !u.isEmpty() )
00524 return u;
00525 }
00526 return KURL();
00527 }
00528
00529 bool Vacation::parseScript( const QString & script, QString & messageText,
00530 int & notificationInterval, QStringList & aliases,
00531 bool & sendForSpam, QString & domainName ) {
00532 if ( script.stripWhiteSpace().isEmpty() ) {
00533 messageText = defaultMessageText();
00534 notificationInterval = defaultNotificationInterval();
00535 aliases = defaultMailAliases();
00536 sendForSpam = defaultSendForSpam();
00537 domainName = defaultDomainName();
00538 return true;
00539 }
00540
00541
00542
00543
00544 const QCString scriptUTF8 = script.stripWhiteSpace().utf8();
00545 kdDebug(5006) << "scriptUtf8 = \"" + scriptUTF8 + "\"" << endl;
00546 KSieve::Parser parser( scriptUTF8.begin(),
00547 scriptUTF8.begin() + scriptUTF8.length() );
00548 VacationDataExtractor vdx;
00549 SpamDataExtractor sdx;
00550 DomainRestrictionDataExtractor drdx;
00551 KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx );
00552 parser.setScriptBuilder( &tsb );
00553 if ( !parser.parse() )
00554 return false;
00555 messageText = vdx.messageText().stripWhiteSpace();
00556 notificationInterval = vdx.notificationInterval();
00557 aliases = vdx.aliases();
00558 if ( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ) {
00559 sendForSpam = !sdx.found();
00560 domainName = drdx.domainName();
00561 }
00562 return true;
00563 }
00564
00565 QString Vacation::defaultMessageText() {
00566 return i18n("I am out of office till %1.\n"
00567 "\n"
00568 "In urgent cases, please contact Mrs. <vacation replacement>\n"
00569 "\n"
00570 "email: <email address of vacation replacement>\n"
00571 "phone: +49 711 1111 11\n"
00572 "fax.: +49 711 1111 12\n"
00573 "\n"
00574 "Yours sincerely,\n"
00575 "-- <enter your name and email address here>\n")
00576 .arg( KGlobal::locale()->formatDate( QDate::currentDate().addDays( 1 ) ) );
00577 }
00578
00579 int Vacation::defaultNotificationInterval() {
00580 return 7;
00581 }
00582
00583 QStringList Vacation::defaultMailAliases() {
00584 QStringList sl;
00585 for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
00586 it != kmkernel->identityManager()->end() ; ++it )
00587 if ( !(*it).emailAddr().isEmpty() )
00588 sl.push_back( (*it).emailAddr() );
00589 return sl;
00590 }
00591
00592 bool Vacation::defaultSendForSpam() {
00593 return GlobalSettings::outOfOfficeReactToSpam();
00594 }
00595
00596 QString Vacation::defaultDomainName() {
00597 return GlobalSettings::outOfOfficeDomain();
00598 }
00599
00600 void Vacation::slotGetResult( SieveJob * job, bool success,
00601 const QString & script, bool active ) {
00602 kdDebug(5006) << "Vacation::slotGetResult( ??, " << success
00603 << ", ?, " << active << " )" << endl
00604 << "script:" << endl
00605 << script << endl;
00606 mSieveJob = 0;
00607
00608 if ( !mCheckOnly && mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() &&
00609 !job->sieveCapabilities().contains("vacation") ) {
00610 KMessageBox::sorry( 0, i18n("Your server did not list \"vacation\" in "
00611 "its list of supported Sieve extensions;\n"
00612 "without it, KMail cannot install out-of-"
00613 "office replies for you.\n"
00614 "Please contact you system administrator.") );
00615 emit result( false );
00616 return;
00617 }
00618
00619 if ( !mDialog && !mCheckOnly )
00620 mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false );
00621
00622 QString messageText = defaultMessageText();
00623 int notificationInterval = defaultNotificationInterval();
00624 QStringList aliases = defaultMailAliases();
00625 bool sendForSpam = defaultSendForSpam();
00626 QString domainName = defaultDomainName();
00627 if ( !success ) active = false;
00628
00629 if ( !mCheckOnly && ( !success || !parseScript( script, messageText, notificationInterval, aliases, sendForSpam, domainName ) ) )
00630 KMessageBox::information( 0, i18n("Someone (probably you) changed the "
00631 "vacation script on the server.\n"
00632 "KMail is no longer able to determine "
00633 "the parameters for the autoreplies.\n"
00634 "Default values will be used." ) );
00635
00636 mWasActive = active;
00637 if ( mDialog ) {
00638 mDialog->setActivateVacation( active );
00639 mDialog->setMessageText( messageText );
00640 mDialog->setNotificationInterval( notificationInterval );
00641 mDialog->setMailAliases( aliases.join(", ") );
00642 mDialog->setSendForSpam( sendForSpam );
00643 mDialog->setDomainName( domainName );
00644 mDialog->enableDomainAndSendForSpam( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() );
00645
00646 connect( mDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) );
00647 connect( mDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCancel()) );
00648 connect( mDialog, SIGNAL(defaultClicked()), SLOT(slotDialogDefaults()) );
00649
00650 mDialog->show();
00651 }
00652
00653 emit scriptActive( mWasActive );
00654 if ( mCheckOnly && mWasActive ) {
00655 if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n"
00656 "Do you want to edit it?"), i18n("Out-of-office reply still active"),
00657 KGuiItem( i18n( "Edit"), "edit" ), KGuiItem( i18n("Ignore"), "button_cancel" ) )
00658 == KMessageBox::Yes ) {
00659 kmkernel->getKMMainWidget()->slotEditVacation();
00660 }
00661 }
00662 }
00663
00664 void Vacation::slotDialogDefaults() {
00665 if ( !mDialog )
00666 return;
00667 mDialog->setActivateVacation( true );
00668 mDialog->setMessageText( defaultMessageText() );
00669 mDialog->setNotificationInterval( defaultNotificationInterval() );
00670 mDialog->setMailAliases( defaultMailAliases().join(", ") );
00671 mDialog->setSendForSpam( defaultSendForSpam() );
00672 mDialog->setDomainName( defaultDomainName() );
00673 }
00674
00675 void Vacation::slotDialogOk() {
00676 kdDebug(5006) << "Vacation::slotDialogOk()" << endl;
00677
00678 const QString script = composeScript( mDialog->messageText(),
00679 mDialog->notificationInterval(),
00680 mDialog->mailAliases(),
00681 mDialog->sendForSpam(),
00682 mDialog->domainName() );
00683 const bool active = mDialog->activateVacation();
00684 emit scriptActive( active );
00685
00686 kdDebug(5006) << "script:" << endl << script << endl;
00687
00688
00689 mSieveJob = SieveJob::put( mUrl, script, active, mWasActive );
00690 connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)),
00691 active
00692 ? SLOT(slotPutActiveResult(KMail::SieveJob*,bool))
00693 : SLOT(slotPutInactiveResult(KMail::SieveJob*,bool)) );
00694
00695
00696 mDialog->delayedDestruct();
00697 mDialog = 0;
00698 }
00699
00700 void Vacation::slotDialogCancel() {
00701 kdDebug(5006) << "Vacation::slotDialogCancel()" << endl;
00702 mDialog->delayedDestruct();
00703 mDialog = 0;
00704 emit result( false );
00705 }
00706
00707 void Vacation::slotPutActiveResult( SieveJob * job, bool success ) {
00708 handlePutResult( job, success, true );
00709 }
00710
00711 void Vacation::slotPutInactiveResult( SieveJob * job, bool success ) {
00712 handlePutResult( job, success, false );
00713 }
00714
00715 void Vacation::handlePutResult( SieveJob *, bool success, bool activated ) {
00716 if ( success )
00717 KMessageBox::information( 0, activated
00718 ? i18n("Sieve script installed successfully on the server.\n"
00719 "Out of Office reply is now active.")
00720 : i18n("Sieve script installed successfully on the server.\n"
00721 "Out of Office reply has been deactivated.") );
00722
00723 kdDebug(5006) << "Vacation::handlePutResult( ???, " << success << ", ? )"
00724 << endl;
00725 mSieveJob = 0;
00726 emit result( success );
00727 emit scriptActive( activated );
00728 }
00729
00730
00731 }
00732
00733 #include "vacation.moc"