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.setQuery( "x-mech=" + (a->auth() == "*" ? "PLAIN" : a->auth()) );
00504 u.setFileName( sieve.vacationFileName() );
00505 return u;
00506 } else {
00507 KURL u = sieve.alternateURL();
00508 u.setFileName( sieve.vacationFileName() );
00509 return u;
00510 }
00511 }
00512
00513 KURL Vacation::findURL() const {
00514 AccountManager * am = kmkernel->acctMgr();
00515 assert( am );
00516 for ( KMAccount * a = am->first() ; a ; a = am->next() )
00517 if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) {
00518 KURL u = findUrlForAccount( iab );
00519 if ( !u.isEmpty() )
00520 return u;
00521 }
00522 return KURL();
00523 }
00524
00525 bool Vacation::parseScript( const QString & script, QString & messageText,
00526 int & notificationInterval, QStringList & aliases,
00527 bool & sendForSpam, QString & domainName ) {
00528 if ( script.stripWhiteSpace().isEmpty() ) {
00529 messageText = defaultMessageText();
00530 notificationInterval = defaultNotificationInterval();
00531 aliases = defaultMailAliases();
00532 sendForSpam = defaultSendForSpam();
00533 domainName = defaultDomainName();
00534 return true;
00535 }
00536
00537
00538
00539
00540 const QCString scriptUTF8 = script.stripWhiteSpace().utf8();
00541 kdDebug(5006) << "scriptUtf8 = \"" + scriptUTF8 + "\"" << endl;
00542 KSieve::Parser parser( scriptUTF8.begin(),
00543 scriptUTF8.begin() + scriptUTF8.length() );
00544 VacationDataExtractor vdx;
00545 SpamDataExtractor sdx;
00546 DomainRestrictionDataExtractor drdx;
00547 KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx );
00548 parser.setScriptBuilder( &tsb );
00549 if ( !parser.parse() )
00550 return false;
00551 messageText = vdx.messageText().stripWhiteSpace();
00552 notificationInterval = vdx.notificationInterval();
00553 aliases = vdx.aliases();
00554 if ( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ) {
00555 sendForSpam = !sdx.found();
00556 domainName = drdx.domainName();
00557 }
00558 return true;
00559 }
00560
00561 QString Vacation::defaultMessageText() {
00562 return i18n("I am out of office till %1.\n"
00563 "\n"
00564 "In urgent cases, please contact Mrs. <vacation replacement>\n"
00565 "\n"
00566 "email: <email address of vacation replacement>\n"
00567 "phone: +49 711 1111 11\n"
00568 "fax.: +49 711 1111 12\n"
00569 "\n"
00570 "Yours sincerely,\n"
00571 "-- <enter your name and email address here>\n")
00572 .arg( KGlobal::locale()->formatDate( QDate::currentDate().addDays( 1 ) ) );
00573 }
00574
00575 int Vacation::defaultNotificationInterval() {
00576 return 7;
00577 }
00578
00579 QStringList Vacation::defaultMailAliases() {
00580 QStringList sl;
00581 for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
00582 it != kmkernel->identityManager()->end() ; ++it )
00583 if ( !(*it).emailAddr().isEmpty() )
00584 sl.push_back( (*it).emailAddr() );
00585 return sl;
00586 }
00587
00588 bool Vacation::defaultSendForSpam() {
00589 return GlobalSettings::outOfOfficeReactToSpam();
00590 }
00591
00592 QString Vacation::defaultDomainName() {
00593 return GlobalSettings::outOfOfficeDomain();
00594 }
00595
00596 void Vacation::slotGetResult( SieveJob * job, bool success,
00597 const QString & script, bool active ) {
00598 kdDebug(5006) << "Vacation::slotGetResult( ??, " << success
00599 << ", ?, " << active << " )" << endl
00600 << "script:" << endl
00601 << script << endl;
00602 mSieveJob = 0;
00603
00604 if ( !mCheckOnly && mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() &&
00605 !job->sieveCapabilities().contains("vacation") ) {
00606 KMessageBox::sorry( 0, i18n("Your server did not list \"vacation\" in "
00607 "its list of supported Sieve extensions;\n"
00608 "without it, KMail cannot install out-of-"
00609 "office replies for you.\n"
00610 "Please contact you system administrator.") );
00611 emit result( false );
00612 return;
00613 }
00614
00615 if ( !mDialog && !mCheckOnly )
00616 mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false );
00617
00618 QString messageText = defaultMessageText();
00619 int notificationInterval = defaultNotificationInterval();
00620 QStringList aliases = defaultMailAliases();
00621 bool sendForSpam = defaultSendForSpam();
00622 QString domainName = defaultDomainName();
00623 if ( !success ) active = false;
00624
00625 if ( !mCheckOnly && ( !success || !parseScript( script, messageText, notificationInterval, aliases, sendForSpam, domainName ) ) )
00626 KMessageBox::information( 0, i18n("Someone (probably you) changed the "
00627 "vacation script on the server.\n"
00628 "KMail is no longer able to determine "
00629 "the parameters for the autoreplies.\n"
00630 "Default values will be used." ) );
00631
00632 mWasActive = active;
00633 if ( mDialog ) {
00634 mDialog->setActivateVacation( active );
00635 mDialog->setMessageText( messageText );
00636 mDialog->setNotificationInterval( notificationInterval );
00637 mDialog->setMailAliases( aliases.join(", ") );
00638 mDialog->setSendForSpam( sendForSpam );
00639 mDialog->setDomainName( domainName );
00640 mDialog->enableDomainAndSendForSpam( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() );
00641
00642 connect( mDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) );
00643 connect( mDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCancel()) );
00644 connect( mDialog, SIGNAL(defaultClicked()), SLOT(slotDialogDefaults()) );
00645
00646 mDialog->show();
00647 }
00648
00649 emit scriptActive( mWasActive );
00650 if ( mCheckOnly && mWasActive ) {
00651 if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n"
00652 "Do you want to edit it?"), i18n("Out-of-office reply still active"),
00653 KGuiItem( i18n( "Edit"), "edit" ), KGuiItem( i18n("Ignore"), "button_cancel" ) )
00654 == KMessageBox::Yes ) {
00655 kmkernel->getKMMainWidget()->slotEditVacation();
00656 }
00657 }
00658 }
00659
00660 void Vacation::slotDialogDefaults() {
00661 if ( !mDialog )
00662 return;
00663 mDialog->setActivateVacation( true );
00664 mDialog->setMessageText( defaultMessageText() );
00665 mDialog->setNotificationInterval( defaultNotificationInterval() );
00666 mDialog->setMailAliases( defaultMailAliases().join(", ") );
00667 mDialog->setSendForSpam( defaultSendForSpam() );
00668 mDialog->setDomainName( defaultDomainName() );
00669 }
00670
00671 void Vacation::slotDialogOk() {
00672 kdDebug(5006) << "Vacation::slotDialogOk()" << endl;
00673
00674 const QString script = composeScript( mDialog->messageText(),
00675 mDialog->notificationInterval(),
00676 mDialog->mailAliases(),
00677 mDialog->sendForSpam(),
00678 mDialog->domainName() );
00679 const bool active = mDialog->activateVacation();
00680 emit scriptActive( active );
00681
00682 kdDebug(5006) << "script:" << endl << script << endl;
00683
00684
00685 mSieveJob = SieveJob::put( mUrl, script, active, mWasActive );
00686 connect( mSieveJob, SIGNAL(gotScript(KMail::SieveJob*,bool,const QString&,bool)),
00687 active
00688 ? SLOT(slotPutActiveResult(KMail::SieveJob*,bool))
00689 : SLOT(slotPutInactiveResult(KMail::SieveJob*,bool)) );
00690
00691
00692 mDialog->delayedDestruct();
00693 mDialog = 0;
00694 }
00695
00696 void Vacation::slotDialogCancel() {
00697 kdDebug(5006) << "Vacation::slotDialogCancel()" << endl;
00698 mDialog->delayedDestruct();
00699 mDialog = 0;
00700 emit result( false );
00701 }
00702
00703 void Vacation::slotPutActiveResult( SieveJob * job, bool success ) {
00704 handlePutResult( job, success, true );
00705 }
00706
00707 void Vacation::slotPutInactiveResult( SieveJob * job, bool success ) {
00708 handlePutResult( job, success, false );
00709 }
00710
00711 void Vacation::handlePutResult( SieveJob *, bool success, bool activated ) {
00712 if ( success )
00713 KMessageBox::information( 0, activated
00714 ? i18n("Sieve script installed successfully on the server.\n"
00715 "Out of Office reply is now active.")
00716 : i18n("Sieve script installed successfully on the server.\n"
00717 "Out of Office reply has been deactivated.") );
00718
00719 kdDebug(5006) << "Vacation::handlePutResult( ???, " << success << ", ? )"
00720 << endl;
00721 mSieveJob = 0;
00722 emit result( success );
00723 emit scriptActive( activated );
00724 }
00725
00726
00727 }
00728
00729 #include "vacation.moc"