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 "kmacctmgr.h"
00027 #include "kmacctimap.h"
00028 #include "kmmessage.h"
00029 #include "identitymanager.h"
00030 #include "kmidentity.h"
00031
00032 #include <kmime_header_parsing.h>
00033 using KMime::Types::AddrSpecList;
00034
00035 #include <ksieve/parser.h>
00036 #include <ksieve/scriptbuilder.h>
00037 #include <ksieve/error.h>
00038
00039 #include <klocale.h>
00040 #include <kmessagebox.h>
00041 #include <kdebug.h>
00042
00043 #include <qdatetime.h>
00044
00045 #include <cassert>
00046
00047 namespace {
00048
00049 class VacationDataExtractor : public KSieve::ScriptBuilder {
00050 enum Context {
00051 None = 0,
00052
00053 VacationCommand,
00054
00055 Days, Addresses
00056 };
00057 public:
00058 VacationDataExtractor()
00059 : KSieve::ScriptBuilder(),
00060 mContext( None ), mNotificationInterval( 0 )
00061 {
00062 kdDebug() << "VacationDataExtractor instantiated" << endl;
00063 }
00064 virtual ~VacationDataExtractor() {}
00065
00066 int notificationInterval() const { return mNotificationInterval; }
00067 const QString & messageText() const { return mMessageText; }
00068 const QStringList & aliases() const { return mAliases; }
00069
00070 private:
00071 void commandStart( const QString & identifier ) {
00072 kdDebug( 5006 ) << "VacationDataExtractor::commandStart( \"" << identifier << "\" )" << endl;
00073 if ( identifier != "vacation" )
00074 return;
00075 reset();
00076 mContext = VacationCommand;
00077 }
00078
00079 void commandEnd() {
00080 kdDebug( 5006 ) << "VacationDataExtractor::commandEnd()" << endl;
00081 mContext = None;
00082 }
00083
00084 void testStart( const QString & ) {}
00085 void testEnd() {}
00086 void testListStart() {}
00087 void testListEnd() {}
00088 void blockStart() {}
00089 void blockEnd() {}
00090 void hashComment( const QString & ) {}
00091 void bracketComment( const QString & ) {}
00092 void lineFeed() {}
00093 void error( const KSieve::Error & e ) {
00094 kdDebug( 5006 ) << "VacationDataExtractor::error() ### "
00095 << e.asString() << " @ " << e.line() << "," << e.column()
00096 << endl;
00097 }
00098 void finished() {}
00099
00100 void taggedArgument( const QString & tag ) {
00101 kdDebug( 5006 ) << "VacationDataExtractor::taggedArgument( \"" << tag << "\" )" << endl;
00102 if ( mContext != VacationCommand )
00103 return;
00104 if ( tag == "days" )
00105 mContext = Days;
00106 else if ( tag == "addresses" )
00107 mContext = Addresses;
00108 }
00109
00110 void stringArgument( const QString & string, bool, const QString & ) {
00111 kdDebug( 5006 ) << "VacationDataExtractor::stringArgument( \"" << string << "\" )" << endl;
00112 if ( mContext == Addresses ) {
00113 mAliases.push_back( string );
00114 mContext = VacationCommand;
00115 } else if ( mContext == VacationCommand ) {
00116 mMessageText = string;
00117 mContext = VacationCommand;
00118 }
00119 }
00120
00121 void numberArgument( unsigned long number, char ) {
00122 kdDebug( 5006 ) << "VacationDataExtractor::numberArgument( \"" << number << "\" )" << endl;
00123 if ( mContext != Days )
00124 return;
00125 if ( number > INT_MAX )
00126 mNotificationInterval = INT_MAX;
00127 else
00128 mNotificationInterval = number;
00129 mContext = VacationCommand;
00130 }
00131
00132 void stringListArgumentStart() {}
00133 void stringListEntry( const QString & string, bool, const QString & ) {
00134 kdDebug( 5006 ) << "VacationDataExtractor::stringListEntry( \"" << string << "\" )" << endl;
00135 if ( mContext != Addresses )
00136 return;
00137 mAliases.push_back( string );
00138 }
00139 void stringListArgumentEnd() {
00140 kdDebug( 5006 ) << "VacationDataExtractor::stringListArgumentEnd()" << endl;
00141 if ( mContext != Addresses )
00142 return;
00143 mContext = VacationCommand;
00144 }
00145
00146 private:
00147 Context mContext;
00148 int mNotificationInterval;
00149 QString mMessageText;
00150 QStringList mAliases;
00151
00152 void reset() {
00153 kdDebug() << "VacationDataExtractor::reset()" << endl;
00154 mContext = None;
00155 mNotificationInterval = 0;
00156 mAliases.clear();
00157 mMessageText = QString::null;
00158 }
00159 };
00160
00161 }
00162
00163 namespace KMail {
00164
00165 Vacation::Vacation( QObject * parent, const char * name )
00166 : QObject( parent, name ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false )
00167 {
00168 mUrl = findURL();
00169 kdDebug(5006) << "Vacation: found url \"" << mUrl.prettyURL() << "\"" << endl;
00170 if ( mUrl.isEmpty() )
00171 return;
00172 mUrl.setFileName( "kmail-vacation.siv" );
00173 mSieveJob = SieveJob::get( mUrl );
00174 connect( mSieveJob, SIGNAL(result(KMail::SieveJob*,bool,const QString&,bool)),
00175 SLOT(slotGetResult(KMail::SieveJob*,bool,const QString&,bool)) );
00176 }
00177
00178 Vacation::~Vacation() {
00179 if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0;
00180 delete mDialog; mDialog = 0;
00181 kdDebug(5006) << "~Vacation()" << endl;
00182 }
00183
00184 static inline QString dotstuff( QString s ) {
00185 if ( s.startsWith( "." ) )
00186 return '.' + s.replace( "\n.", "\n.." );
00187 else
00188 return s.replace( "\n.", "\n.." );
00189 }
00190
00191 QString Vacation::composeScript( const QString & messageText,
00192 int notificationInterval,
00193 const AddrSpecList & addrSpecs )
00194 {
00195 QString addressesArgument;
00196 QStringList aliases;
00197 if ( !addrSpecs.empty() ) {
00198 addressesArgument += ":addresses [ ";
00199 QStringList sl;
00200 for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != addrSpecs.end() ; ++it ) {
00201 sl.push_back( '"' + (*it).asString().replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"' );
00202 aliases.push_back( (*it).asString() );
00203 }
00204 addressesArgument += sl.join( ", " ) + " ] ";
00205 }
00206 QString script = QString::fromLatin1("require \"vacation\";\n"
00207 "\n"
00208 "vacation ");
00209 script += addressesArgument;
00210 if ( notificationInterval > 0 )
00211 script += QString::fromLatin1(":days %1 ").arg( notificationInterval );
00212 script += QString::fromLatin1("text:\n");
00213 script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText );
00214 script += QString::fromLatin1( "\n.\n;\n" );
00215 return script;
00216 }
00217
00218 static KURL findUrlForAccount( const KMail::ImapAccountBase * a ) {
00219 assert( a );
00220 SieveConfig sieve = a->sieveConfig();
00221 if ( !sieve.managesieveSupported() )
00222 return KURL();
00223 if ( sieve.reuseConfig() ) {
00224
00225 KURL u;
00226 u.setProtocol( "sieve" );
00227 u.setHost( a->host() );
00228 u.setUser( a->login() );
00229 u.setPass( a->passwd() );
00230 u.setPort( sieve.port() );
00231 return u;
00232 } else {
00233 return sieve.alternateURL();
00234 }
00235 }
00236
00237 KURL Vacation::findURL() const {
00238 KMAcctMgr * am = kmkernel->acctMgr();
00239 assert( am );
00240 for ( KMAccount * a = am->first() ; a ; a = am->next() )
00241 if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) {
00242 KURL u = findUrlForAccount( iab );
00243 if ( !u.isEmpty() )
00244 return u;
00245 }
00246 return KURL();
00247 }
00248
00249 bool Vacation::parseScript( const QString & script, QString & messageText,
00250 int & notificationInterval, QStringList & aliases ) {
00251 if ( script.stripWhiteSpace().isEmpty() ) {
00252 messageText = defaultMessageText();
00253 notificationInterval = defaultNotificationInterval();
00254 aliases = defaultMailAliases();
00255 return true;
00256 }
00257
00258
00259
00260
00261 const QCString scriptUTF8 = script.stripWhiteSpace().utf8();
00262 kdDebug() << "scriptUtf8 = \"" + scriptUTF8 + "\"" << endl;
00263 KSieve::Parser parser( scriptUTF8.begin(),
00264 scriptUTF8.begin() + scriptUTF8.length() );
00265 VacationDataExtractor vdx;
00266 parser.setScriptBuilder( &vdx );
00267 if ( !parser.parse() )
00268 return false;
00269 messageText = vdx.messageText().stripWhiteSpace();
00270 notificationInterval = vdx.notificationInterval();
00271 aliases = vdx.aliases();
00272 return true;
00273 }
00274
00275 QString Vacation::defaultMessageText() {
00276 return i18n("I am out of office till %1.\n"
00277 "\n"
00278 "In urgent cases, please contact Mrs. <vacation replacement>\n"
00279 "\n"
00280 "email: <email address of vacation replacement>\n"
00281 "phone: +49 711 1111 11\n"
00282 "fax.: +49 711 1111 12\n"
00283 "\n"
00284 "Yours sincerely,\n"
00285 "-- <enter your name and email address here>\n")
00286 .arg( KGlobal::locale()->formatDate( QDate::currentDate().addDays( 1 ) ) );
00287 }
00288
00289 int Vacation::defaultNotificationInterval() {
00290 return 7;
00291 }
00292
00293 QStringList Vacation::defaultMailAliases() {
00294 QStringList sl;
00295 for ( IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
00296 it != kmkernel->identityManager()->end() ; ++it )
00297 if ( !(*it).emailAddr().isEmpty() )
00298 sl.push_back( (*it).emailAddr() );
00299 return sl;
00300 }
00301
00302
00303 void Vacation::slotGetResult( SieveJob * job, bool success,
00304 const QString & script, bool active ) {
00305 kdDebug(5006) << "Vacation::slotGetResult( ??, " << success
00306 << ", ?, " << active << " )" << endl
00307 << "script:" << endl
00308 << script << endl;
00309 mSieveJob = 0;
00310
00311 if ( mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() &&
00312 !job->sieveCapabilities().contains("vacation") ) {
00313 KMessageBox::sorry( 0, i18n("Your server didn't list \"vacation\" in "
00314 "it's list of supported Sieve extensions.\n"
00315 "Without it, KMail cannot install out of "
00316 "office replies for you.\n"
00317 "Please contact you system administrator.") );
00318 emit result( false );
00319 return;
00320 }
00321
00322 if ( !mDialog )
00323 mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false );
00324
00325 QString messageText = defaultMessageText();
00326 int notificationInterval = defaultNotificationInterval();
00327 QStringList aliases = defaultMailAliases();
00328 if ( !success ) active = false;
00329
00330 if ( !success || !parseScript( script, messageText, notificationInterval, aliases ) )
00331 KMessageBox::information( 0, i18n("Someone (probably you) changed the "
00332 "vacation script on the server.\n"
00333 "KMail is no longer able to determine "
00334 "the parameters for the autoreplies.\n"
00335 "Default values will be used." ) );
00336
00337 mWasActive = active;
00338 mDialog->setActivateVacation( active );
00339 mDialog->setMessageText( messageText );
00340 mDialog->setNotificationInterval( notificationInterval );
00341 mDialog->setMailAliases( aliases.join(", ") );
00342
00343 connect( mDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) );
00344 connect( mDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCancel()) );
00345 connect( mDialog, SIGNAL(defaultClicked()), SLOT(slotDialogDefaults()) );
00346
00347 mDialog->show();
00348 }
00349
00350 void Vacation::slotDialogDefaults() {
00351 if ( !mDialog )
00352 return;
00353 mDialog->setActivateVacation( true );
00354 mDialog->setMessageText( defaultMessageText() );
00355 mDialog->setNotificationInterval( defaultNotificationInterval() );
00356 mDialog->setMailAliases( defaultMailAliases().join(", ") );
00357 }
00358
00359 void Vacation::slotDialogOk() {
00360 kdDebug(5006) << "Vacation::slotDialogOk()" << endl;
00361
00362 const QString script = composeScript( mDialog->messageText(),
00363 mDialog->notificationInterval(),
00364 mDialog->mailAliases() );
00365 const bool active = mDialog->activateVacation();
00366
00367 kdDebug(5006) << "script:" << endl << script << endl;
00368
00369
00370 mSieveJob = SieveJob::put( mUrl, script, active, mWasActive );
00371 connect( mSieveJob, SIGNAL(result(KMail::SieveJob*,bool,const QString&,bool)),
00372 SLOT(slotPutResult(KMail::SieveJob*,bool,const QString&,bool)) );
00373
00374
00375 mDialog->delayedDestruct();
00376 mDialog = 0;
00377 }
00378
00379 void Vacation::slotDialogCancel() {
00380 kdDebug(5006) << "Vacation::slotDialogCancel()" << endl;
00381 mDialog->delayedDestruct();
00382 mDialog = 0;
00383 emit result( false );
00384 }
00385
00386 void Vacation::slotPutResult( SieveJob *, bool success, const QString &, bool ) {
00387 if ( success )
00388 KMessageBox::information( 0, i18n("Out of Office reply installed successfully.") );
00389 kdDebug(5006) << "Vacation::slotPutResult( ???, " << success << ", ?, ? )"
00390 << endl;
00391 mSieveJob = 0;
00392 emit result( success );
00393 }
00394
00395
00396 }
00397
00398 #include "vacation.moc"