kmail Library API Documentation

vacation.cpp

00001 /*  -*- c++ -*-
00002     vacation.cpp
00003 
00004     KMail, the KDE mail client.
00005     Copyright (c) 2002 Marc Mutz <mutz@kde.org>
00006 
00007     This program is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU General Public License,
00009     version 2.0, as published by the Free Software Foundation.
00010     You should have received a copy of the GNU General Public License
00011     along with this program; if not, write to the Free Software Foundation,
00012     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, US
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       // command itself:
00053       VacationCommand,
00054       // tagged args:
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() ) // nothing to do...
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       // assemble Sieve url from the settings of the account:
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     // The stripWhiteSpace() call below prevents parsing errors. The
00259     // slave somehow omits the last \n, which results in a lone \r at
00260     // the end, leading to a parse error.
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; // days
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; // job deletes itself after returning from this slot!
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; // default to inactive
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     // compose a new script:
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     // and commit the dialog's settings to the server:
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     // destroy the dialog:
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; // job deletes itself after returning from this slot!
00392     emit result( success );
00393   }
00394 
00395 
00396 } // namespace KMail
00397 
00398 #include "vacation.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:35 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003