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 <libkpimidentities/identitymanager.h>
00030
#include <libkpimidentities/identity.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(5006) <<
"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(5006) <<
"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(5006) <<
"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 ( KPIM::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 did not list \"vacation\" in "
00314
"its 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 active
00373 ? SLOT(slotPutActiveResult(KMail::SieveJob*,
bool))
00374 : SLOT(slotPutInactiveResult(KMail::SieveJob*,
bool)) );
00375
00376
00377 mDialog->delayedDestruct();
00378 mDialog = 0;
00379 }
00380
00381
void Vacation::slotDialogCancel() {
00382 kdDebug(5006) <<
"Vacation::slotDialogCancel()" << endl;
00383 mDialog->delayedDestruct();
00384 mDialog = 0;
00385 emit result(
false );
00386 }
00387
00388
void Vacation::slotPutActiveResult( SieveJob * job,
bool success ) {
00389 handlePutResult( job, success,
true );
00390 }
00391
00392
void Vacation::slotPutInactiveResult( SieveJob * job,
bool success ) {
00393 handlePutResult( job, success,
false );
00394 }
00395
00396
void Vacation::handlePutResult( SieveJob *,
bool success,
bool activated ) {
00397
if ( success )
00398 KMessageBox::information( 0, activated
00399 ? i18n(
"Sieve script installed successfully on the server.\n"
00400
"Out of Office reply is now active.")
00401 : i18n(
"Sieve script installed successfully on the server.\n"
00402
"Out of Office reply has been deactivated.") );
00403
00404 kdDebug(5006) <<
"Vacation::handlePutResult( ???, " << success <<
", ? )"
00405 << endl;
00406 mSieveJob = 0;
00407 emit result( success );
00408 }
00409
00410
00411 }
00412
00413
#include "vacation.moc"