kmail

vacation.cpp
1 /*
2  vacation.cpp
3 
4  KMail, the KDE mail client.
5  Copyright (c) 2002 Marc Mutz <mutz@kde.org>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License,
9  version 2.0, as published by the Free Software Foundation.
10  You should have received a copy of the GNU General Public License
11  along with this program; if not, write to the Free Software Foundation,
12  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
13 */
14 
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18 
19 #include "vacation.h"
20 #include <limits.h>
21 
22 #include "vacationdialog.h"
23 #include "sievejob.h"
24 using KMail::SieveJob;
25 #include "kmkernel.h"
26 #include "kmmainwidget.h"
27 #include "accountmanager.h"
29 #include "kmacctimap.h"
30 #include "kmmessage.h"
31 #include "globalsettings.h"
32 #include <libkpimidentities/identitymanager.h>
33 #include <libkpimidentities/identity.h>
34 
35 #include <kmime_header_parsing.h>
36 using KMime::Types::AddrSpecList;
37 
38 #include <ksieve/parser.h>
39 #include <ksieve/scriptbuilder.h>
40 #include <ksieve/error.h>
41 
42 #include <tdelocale.h>
43 #include <tdemessagebox.h>
44 #include <kdebug.h>
45 
46 #include <tqdatetime.h>
47 
48 #include <cassert>
49 #include <vector>
50 #include <map>
51 #include <set>
52 
53 namespace KSieveExt {
54 
55  class MultiScriptBuilder : public KSieve::ScriptBuilder {
56  std::vector<KSieve::ScriptBuilder*> mBuilders;
57  public:
58  MultiScriptBuilder() : KSieve::ScriptBuilder() {}
59  MultiScriptBuilder( KSieve::ScriptBuilder * sb1 )
60  : KSieve::ScriptBuilder(), mBuilders( 1 )
61  {
62  mBuilders[0] = sb1;
63  assert( sb1 );
64  }
65  MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
66  KSieve::ScriptBuilder * sb2 )
67  : KSieve::ScriptBuilder(), mBuilders( 2 )
68  {
69  mBuilders[0] = sb1;
70  mBuilders[1] = sb2;
71  assert( sb1 ); assert( sb2 );
72  }
73  MultiScriptBuilder( KSieve::ScriptBuilder * sb1,
74  KSieve::ScriptBuilder * sb2,
75  KSieve::ScriptBuilder * sb3 )
76  : KSieve::ScriptBuilder(), mBuilders( 3 )
77  {
78  mBuilders[0] = sb1;
79  mBuilders[1] = sb2;
80  mBuilders[2] = sb3;
81  assert( sb1 ); assert( sb2 ); assert( sb3 );
82  }
83  ~MultiScriptBuilder() {}
84  private:
85 #ifdef FOREACH
86 #undef FOREACH
87 #endif
88 #define FOREACH for ( std::vector<KSieve::ScriptBuilder*>::const_iterator it = mBuilders.begin(), end = mBuilders.end() ; it != end ; ++it ) (*it)->
89  void commandStart( const TQString & identifier ) { FOREACH commandStart( identifier ); }
90  void commandEnd() { FOREACH commandEnd(); }
91  void testStart( const TQString & identifier ) { FOREACH testStart( identifier ); }
92  void testEnd() { FOREACH testEnd(); }
93  void testListStart() { FOREACH testListStart(); }
94  void testListEnd() { FOREACH testListEnd(); }
95  void blockStart() { FOREACH blockStart(); }
96  void blockEnd() { FOREACH blockEnd(); }
97  void hashComment( const TQString & comment ) { FOREACH hashComment( comment ); }
98  void bracketComment( const TQString & comment ) { FOREACH bracketComment( comment ); }
99  void lineFeed() { FOREACH lineFeed(); }
100  void error( const KSieve::Error & e ) { FOREACH error( e ); }
101  void finished() { FOREACH finished(); }
102  void taggedArgument( const TQString & tag ) { FOREACH taggedArgument( tag ); }
103  void stringArgument( const TQString & string, bool multiline, const TQString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); }
104  void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); }
105  void stringListArgumentStart() { FOREACH stringListArgumentStart(); }
106  void stringListEntry( const TQString & string, bool multiline, const TQString & fixme) { FOREACH stringListEntry( string, multiline, fixme ); }
107  void stringListArgumentEnd() { FOREACH stringListArgumentEnd(); }
108 #undef FOREACH
109  };
110 
111 }
112 
113 namespace {
114 
115  class GenericInformationExtractor : public KSieve::ScriptBuilder {
116  public:
117  enum BuilderMethod {
118  Any,
119  TaggedArgument,
120  StringArgument,
121  NumberArgument,
122  CommandStart,
123  CommandEnd,
124  TestStart,
125  TestEnd,
126  TestListStart,
127  TestListEnd,
128  BlockStart,
129  BlockEnd,
130  StringListArgumentStart,
131  StringListEntry,
132  StringListArgumentEnd
133  };
134 
135  struct StateNode {
136  // expectation:
137  int depth;
138  BuilderMethod method;
139  const char * string;
140  // actions:
141  int if_found;
142  int if_not_found;
143  const char * save_tag;
144  };
145 
146  const std::vector<StateNode> mNodes;
147  std::map<TQString,TQString> mResults;
148  std::set<unsigned int> mRecursionGuard;
149  unsigned int mState;
150  int mNestingDepth;
151 
152  public:
153  GenericInformationExtractor( const std::vector<StateNode> & nodes )
154  : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ) {}
155 
156  const std::map<TQString,TQString> & results() const { return mResults; }
157 
158  private:
159  void process( BuilderMethod method, const TQString & string=TQString() ) {
160  doProcess( method, string );
161  mRecursionGuard.clear();
162  }
163  void doProcess( BuilderMethod method, const TQString & string ) {
164  mRecursionGuard.insert( mState );
165  bool found = true;
166  const StateNode & expected = mNodes[mState];
167  if ( expected.depth != -1 && mNestingDepth != expected.depth )
168  found = false;
169  if ( expected.method != Any && method != expected.method )
170  found = false;
171  if ( const char * str = expected.string )
172  if ( string.lower() != TQString::fromUtf8( str ).lower() )
173  found = false;
174  kdDebug(5006) << ( found ? "found: " : "not found: " )
175  << mState << " -> "
176  << ( found ? expected.if_found : expected.if_not_found ) << endl;
177  mState = found ? expected.if_found : expected.if_not_found ;
178  assert( mState < mNodes.size() );
179  if ( found )
180  if ( const char * save_tag = expected.save_tag )
181  mResults[save_tag] = string;
182  if ( !found && !mRecursionGuard.count( mState ) ) {
183  doProcess( method, string );
184  }
185  }
186  void commandStart( const TQString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( CommandStart, identifier ); }
187  void commandEnd() { kdDebug(5006) << k_funcinfo << endl; process( CommandEnd ); }
188  void testStart( const TQString & identifier ) { kdDebug(5006) << k_funcinfo << endl; process( TestStart, identifier ); }
189  void testEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestEnd ); }
190  void testListStart() { kdDebug(5006) << k_funcinfo << endl; process( TestListStart ); }
191  void testListEnd() { kdDebug(5006) << k_funcinfo << endl; process( TestListEnd ); }
192  void blockStart() { kdDebug(5006) << k_funcinfo << endl; process( BlockStart ); ++mNestingDepth; }
193  void blockEnd() { kdDebug(5006) << k_funcinfo << endl; --mNestingDepth; process( BlockEnd ); }
194  void hashComment( const TQString & ) { kdDebug(5006) << k_funcinfo << endl; }
195  void bracketComment( const TQString & ) { kdDebug(5006) << k_funcinfo << endl; }
196  void lineFeed() { kdDebug(5006) << k_funcinfo << endl; }
197  void error( const KSieve::Error & ) {
198  kdDebug(5006) << k_funcinfo << endl;
199  mState = 0;
200  }
201  void finished() { kdDebug(5006) << k_funcinfo << endl; }
202 
203  void taggedArgument( const TQString & tag ) { kdDebug(5006) << k_funcinfo << endl; process( TaggedArgument, tag ); }
204  void stringArgument( const TQString & string, bool, const TQString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringArgument, string ); }
205  void numberArgument( unsigned long number, char ) { kdDebug(5006) << k_funcinfo << endl; process( NumberArgument, TQString::number( number ) ); }
206  void stringListArgumentStart() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentStart ); }
207  void stringListEntry( const TQString & string, bool, const TQString & ) { kdDebug(5006) << k_funcinfo << endl; process( StringListEntry, string ); }
208  void stringListArgumentEnd() { kdDebug(5006) << k_funcinfo << endl; process( StringListArgumentEnd ); }
209  };
210 
211  typedef GenericInformationExtractor GIE;
212  static const GenericInformationExtractor::StateNode spamNodes[] = {
213  { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0
214  { 0, GIE::TestStart, "header", 2, 0, 0 }, // 1
215  { 0, GIE::TaggedArgument, "contains", 3, 0, 0 }, // 2
216 
217  // accept both string and string-list:
218  { 0, GIE::StringArgument, "x-spam-flag", 9, 4, "x-spam-flag" }, // 3
219  { 0, GIE::StringListArgumentStart, 0, 5, 0, 0 }, // 4
220  { 0, GIE::StringListEntry, "x-spam-flag", 6, 7, "x-spam-flag" }, // 5
221  { 0, GIE::StringListEntry, 0, 6, 8, 0 }, // 6
222  { 0, GIE::StringListArgumentEnd, 0, 0, 5, 0 }, // 7
223  { 0, GIE::StringListArgumentEnd, 0, 9, 0, 0 }, // 8
224 
225  // accept both string and string-list:
226  { 0, GIE::StringArgument, "yes", 15, 10, "spam-flag-yes" }, // 9
227  { 0, GIE::StringListArgumentStart, 0, 11, 0, 0 }, // 10
228  { 0, GIE::StringListEntry, "yes", 12, 13, "spam-flag-yes" }, // 11
229  { 0, GIE::StringListEntry, 0, 12, 14, 0 }, // 12
230  { 0, GIE::StringListArgumentEnd, 0, 0, 11, 0 }, // 13
231  { 0, GIE::StringListArgumentEnd, 0, 15, 0, 0 }, // 14
232 
233  { 0, GIE::TestEnd, 0, 16, 0, 0 }, // 15
234 
235  // block of command, find "stop", take nested if's into account:
236  { 0, GIE::BlockStart, 0, 17, 0, 0 }, // 16
237  { 1, GIE::CommandStart, "stop", 20, 19, "stop" }, // 17
238  { -1, GIE::Any, 0, 17, 0, 0 }, // 18
239  { 0, GIE::BlockEnd, 0, 0, 18, 0 }, // 19
240 
241  { -1, GIE::Any, 0, 20, 20, 0 }, // 20 end state
242  };
243  static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ;
244 
245  class SpamDataExtractor : public GenericInformationExtractor {
246  public:
247  SpamDataExtractor()
248  : GenericInformationExtractor( std::vector<StateNode>( spamNodes, spamNodes + numSpamNodes ) )
249  {
250 
251  }
252 
253  bool found() const {
254  return mResults.count( "x-spam-flag" ) &&
255  mResults.count( "spam-flag-yes" ) &&
256  mResults.count( "stop" ) ;
257  }
258  };
259 
260  // to understand this table, study the output of
261  // libksieve/tests/parsertest
262  // 'if not address :domain :contains ["from"] ["mydomain.org"] { keep; stop; }'
263  static const GenericInformationExtractor::StateNode domainNodes[] = {
264  { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0
265  { 0, GIE::TestStart, "not", 2, 0, 0, }, // 1
266  { 0, GIE::TestStart, "address", 3, 0, 0 }, // 2
267 
268  // :domain and :contains in arbitrary order:
269  { 0, GIE::TaggedArgument, "domain", 4, 5, 0 }, // 3
270  { 0, GIE::TaggedArgument, "contains", 7, 0, 0 }, // 4
271  { 0, GIE::TaggedArgument, "contains", 6, 0, 0 }, // 5
272  { 0, GIE::TaggedArgument, "domain", 7, 0, 0 }, // 6
273 
274  // accept both string and string-list:
275  { 0, GIE::StringArgument, "from", 13, 8, "from" }, // 7
276  { 0, GIE::StringListArgumentStart, 0, 9, 0, 0 }, // 8
277  { 0, GIE::StringListEntry, "from", 10, 11, "from" }, // 9
278  { 0, GIE::StringListEntry, 0, 10, 12, 0 }, // 10
279  { 0, GIE::StringListArgumentEnd, 0, 0, 9, 0 }, // 11
280  { 0, GIE::StringListArgumentEnd, 0, 13, 0, 0 }, // 12
281 
282  // string: save, string-list: save last
283  { 0, GIE::StringArgument, 0, 17, 14, "domainName" }, // 13
284  { 0, GIE::StringListArgumentStart, 0, 15, 0, 0 }, // 14
285  { 0, GIE::StringListEntry, 0, 15, 16, "domainName" }, // 15
286  { 0, GIE::StringListArgumentEnd, 0, 17, 0, 0 }, // 16
287 
288  { 0, GIE::TestEnd, 0, 18, 0, 0 }, // 17
289  { 0, GIE::TestEnd, 0, 19, 0, 0 }, // 18
290 
291  // block of commands, find "stop", take nested if's into account:
292  { 0, GIE::BlockStart, 0, 20, 0, 0 }, // 19
293  { 1, GIE::CommandStart, "stop", 23, 22, "stop" }, // 20
294  { -1, GIE::Any, 0, 20, 0, 0 }, // 21
295  { 0, GIE::BlockEnd, 0, 0, 21, 0 }, // 22
296 
297  { -1, GIE::Any, 0, 23, 23, 0 } // 23 end state
298  };
299  static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ;
300 
301  class DomainRestrictionDataExtractor : public GenericInformationExtractor {
302  public:
303  DomainRestrictionDataExtractor()
304  : GenericInformationExtractor( std::vector<StateNode>( domainNodes, domainNodes+numDomainNodes ) )
305  {
306 
307  }
308 
309  TQString domainName() /*not const, since map::op[] isn't const*/ {
310  return mResults.count( "stop" ) && mResults.count( "from" )
311  ? mResults["domainName"] : TQString() ;
312  }
313  };
314 
315  class VacationDataExtractor : public KSieve::ScriptBuilder {
316  enum Context {
317  None = 0,
318  // command itself:
319  VacationCommand,
320  // tagged args:
321  Days, Addresses
322  };
323  public:
324  VacationDataExtractor()
325  : KSieve::ScriptBuilder(),
326  mContext( None ), mNotificationInterval( 0 )
327  {
328  kdDebug(5006) << "VacationDataExtractor instantiated" << endl;
329  }
330  virtual ~VacationDataExtractor() {}
331 
332  int notificationInterval() const { return mNotificationInterval; }
333  const TQString & messageText() const { return mMessageText; }
334  const TQStringList & aliases() const { return mAliases; }
335 
336  private:
337  void commandStart( const TQString & identifier ) {
338  kdDebug( 5006 ) << "VacationDataExtractor::commandStart( \"" << identifier << "\" )" << endl;
339  if ( identifier != "vacation" )
340  return;
341  reset();
342  mContext = VacationCommand;
343  }
344 
345  void commandEnd() {
346  kdDebug( 5006 ) << "VacationDataExtractor::commandEnd()" << endl;
347  mContext = None;
348  }
349 
350  void testStart( const TQString & ) {}
351  void testEnd() {}
352  void testListStart() {}
353  void testListEnd() {}
354  void blockStart() {}
355  void blockEnd() {}
356  void hashComment( const TQString & ) {}
357  void bracketComment( const TQString & ) {}
358  void lineFeed() {}
359  void error( const KSieve::Error & e ) {
360  kdDebug( 5006 ) << "VacationDataExtractor::error() ### "
361  << e.asString() << " @ " << e.line() << "," << e.column()
362  << endl;
363  }
364  void finished() {}
365 
366  void taggedArgument( const TQString & tag ) {
367  kdDebug( 5006 ) << "VacationDataExtractor::taggedArgument( \"" << tag << "\" )" << endl;
368  if ( mContext != VacationCommand )
369  return;
370  if ( tag == "days" )
371  mContext = Days;
372  else if ( tag == "addresses" )
373  mContext = Addresses;
374  }
375 
376  void stringArgument( const TQString & string, bool, const TQString & ) {
377  kdDebug( 5006 ) << "VacationDataExtractor::stringArgument( \"" << string << "\" )" << endl;
378  if ( mContext == Addresses ) {
379  mAliases.push_back( string );
380  mContext = VacationCommand;
381  } else if ( mContext == VacationCommand ) {
382  mMessageText = string;
383  mContext = VacationCommand;
384  }
385  }
386 
387  void numberArgument( unsigned long number, char ) {
388  kdDebug( 5006 ) << "VacationDataExtractor::numberArgument( \"" << number << "\" )" << endl;
389  if ( mContext != Days )
390  return;
391  if ( number > INT_MAX )
392  mNotificationInterval = INT_MAX;
393  else
394  mNotificationInterval = number;
395  mContext = VacationCommand;
396  }
397 
398  void stringListArgumentStart() {}
399  void stringListEntry( const TQString & string, bool, const TQString & ) {
400  kdDebug( 5006 ) << "VacationDataExtractor::stringListEntry( \"" << string << "\" )" << endl;
401  if ( mContext != Addresses )
402  return;
403  mAliases.push_back( string );
404  }
405  void stringListArgumentEnd() {
406  kdDebug( 5006 ) << "VacationDataExtractor::stringListArgumentEnd()" << endl;
407  if ( mContext != Addresses )
408  return;
409  mContext = VacationCommand;
410  }
411 
412  private:
413  Context mContext;
414  int mNotificationInterval;
415  TQString mMessageText;
416  TQStringList mAliases;
417 
418  void reset() {
419  kdDebug(5006) << "VacationDataExtractor::reset()" << endl;
420  mContext = None;
421  mNotificationInterval = 0;
422  mAliases.clear();
423  mMessageText = TQString();
424  }
425  };
426 
427 }
428 
429 namespace KMail {
430 
431  Vacation::Vacation( TQObject * parent, bool checkOnly, const char * name )
432  : TQObject( parent, name ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false ), mCheckOnly( checkOnly )
433  {
434  mUrl = findURL();
435  kdDebug(5006) << "Vacation: found url \"" << mUrl.prettyURL() << "\"" << endl;
436  if ( mUrl.isEmpty() ) // nothing to do...
437  return;
438  mSieveJob = SieveJob::get( mUrl, !checkOnly );
439  connect( mSieveJob, TQ_SIGNAL(gotScript(KMail::SieveJob*,bool,const TQString&,bool)),
440  TQ_SLOT(slotGetResult(KMail::SieveJob*,bool,const TQString&,bool)) );
441  }
442 
443  Vacation::~Vacation() {
444  if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0;
445  delete mDialog; mDialog = 0;
446  kdDebug(5006) << "~Vacation()" << endl;
447  }
448 
449  static inline TQString dotstuff( TQString s ) {
450  if ( s.startsWith( "." ) )
451  return '.' + s.replace( "\n.", "\n.." );
452  else
453  return s.replace( "\n.", "\n.." );
454  }
455 
456  TQString Vacation::composeScript( const TQString & messageText,
457  int notificationInterval,
458  const AddrSpecList & addrSpecs,
459  bool sendForSpam, const TQString & domain )
460  {
461  TQString addressesArgument;
462  TQStringList aliases;
463  if ( !addrSpecs.empty() ) {
464  addressesArgument += ":addresses [ ";
465  TQStringList sl;
466  for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != addrSpecs.end() ; ++it ) {
467  sl.push_back( '"' + (*it).asString().replace( '\\', "\\\\" ).replace( '"', "\\\"" ) + '"' );
468  aliases.push_back( (*it).asString() );
469  }
470  addressesArgument += sl.join( ", " ) + " ] ";
471  }
472  TQString script = TQString::fromLatin1("require \"vacation\";\n\n" );
473  if ( !sendForSpam )
474  script += TQString::fromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\""
475  " { keep; stop; }\n" ); // FIXME?
476 
477  if ( !domain.isEmpty() ) // FIXME
478  script += TQString::fromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).arg( domain );
479 
480  script += "vacation ";
481  script += addressesArgument;
482  if ( notificationInterval > 0 )
483  script += TQString::fromLatin1(":days %1 ").arg( notificationInterval );
484  script += TQString::fromLatin1("text:\n");
485  script += dotstuff( messageText.isEmpty() ? defaultMessageText() : messageText );
486  script += TQString::fromLatin1( "\n.\n;\n" );
487  return script;
488  }
489 
490  static KURL findUrlForAccount( const KMail::ImapAccountBase * a ) {
491  assert( a );
492  const SieveConfig sieve = a->sieveConfig();
493  if ( !sieve.managesieveSupported() )
494  return KURL();
495  if ( sieve.reuseConfig() ) {
496  // assemble Sieve url from the settings of the account:
497  KURL u;
498  u.setProtocol( "sieve" );
499  u.setHost( a->host() );
500  u.setUser( a->login() );
501  u.setPass( a->passwd() );
502  u.setPort( sieve.port() );
503  u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() ); //translate IMAP LOGIN to PLAIN
504  if ( !a->useSSL() && !a->useTLS() )
505  u.addQueryItem( "x-allow-unencrypted", "true" );
506  u.setFileName( sieve.vacationFileName() );
507  return u;
508  } else {
509  KURL u = sieve.alternateURL();
510  if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
511  u.addQueryItem( "x-allow-unencrypted", "true" );
512  u.setFileName( sieve.vacationFileName() );
513  return u;
514  }
515  }
516 
517  KURL Vacation::findURL() const {
518  AccountManager * am = kmkernel->acctMgr();
519  assert( am );
520  for ( KMAccount * a = am->first() ; a ; a = am->next() )
521  if ( KMail::ImapAccountBase * iab = dynamic_cast<KMail::ImapAccountBase*>( a ) ) {
522  KURL u = findUrlForAccount( iab );
523  if ( !u.isEmpty() )
524  return u;
525  }
526  return KURL();
527  }
528 
529  bool Vacation::parseScript( const TQString & script, TQString & messageText,
530  int & notificationInterval, TQStringList & aliases,
531  bool & sendForSpam, TQString & domainName ) {
532  if ( script.stripWhiteSpace().isEmpty() ) {
533  messageText = defaultMessageText();
534  notificationInterval = defaultNotificationInterval();
535  aliases = defaultMailAliases();
536  sendForSpam = defaultSendForSpam();
537  domainName = defaultDomainName();
538  return true;
539  }
540 
541  // The stripWhiteSpace() call below prevents parsing errors. The
542  // slave somehow omits the last \n, which results in a lone \r at
543  // the end, leading to a parse error.
544  const TQCString scriptUTF8 = script.stripWhiteSpace().utf8();
545  kdDebug(5006) << "scriptUtf8 = \"" + scriptUTF8 + "\"" << endl;
546  KSieve::Parser parser( scriptUTF8.begin(),
547  scriptUTF8.begin() + scriptUTF8.length() );
548  VacationDataExtractor vdx;
549  SpamDataExtractor sdx;
550  DomainRestrictionDataExtractor drdx;
551  KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx );
552  parser.setScriptBuilder( &tsb );
553  if ( !parser.parse() )
554  return false;
555  messageText = vdx.messageText().stripWhiteSpace();
556  notificationInterval = vdx.notificationInterval();
557  aliases = vdx.aliases();
558  if ( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() ) {
559  sendForSpam = !sdx.found();
560  domainName = drdx.domainName();
561  }
562  return true;
563  }
564 
565  TQString Vacation::defaultMessageText() {
566  return i18n("I am out of office till %1.\n"
567  "\n"
568  "In urgent cases, please contact Mrs. <vacation replacement>\n"
569  "\n"
570  "email: <email address of vacation replacement>\n"
571  "phone: +49 711 1111 11\n"
572  "fax.: +49 711 1111 12\n"
573  "\n"
574  "Yours sincerely,\n"
575  "-- <enter your name and email address here>\n")
576  .arg( TDEGlobal::locale()->formatDate( TQDate::currentDate().addDays( 1 ) ) );
577  }
578 
579  int Vacation::defaultNotificationInterval() {
580  return 7; // days
581  }
582 
583  TQStringList Vacation::defaultMailAliases() {
584  TQStringList sl;
585  for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
586  it != kmkernel->identityManager()->end() ; ++it ) {
587  if ( !(*it).primaryEmailAddress().isEmpty() )
588  sl.push_back( (*it).primaryEmailAddress() );
589  sl += (*it).emailAliases();
590  }
591  return sl;
592  }
593 
594  bool Vacation::defaultSendForSpam() {
595  return GlobalSettings::outOfOfficeReactToSpam();
596  }
597 
598  TQString Vacation::defaultDomainName() {
599  return GlobalSettings::outOfOfficeDomain();
600  }
601 
602  void Vacation::slotGetResult( SieveJob * job, bool success,
603  const TQString & script, bool active ) {
604  kdDebug(5006) << "Vacation::slotGetResult( ??, " << success
605  << ", ?, " << active << " )" << endl
606  << "script:" << endl
607  << script << endl;
608  mSieveJob = 0; // job deletes itself after returning from this slot!
609 
610  if ( !mCheckOnly && mUrl.protocol() == "sieve" && !job->sieveCapabilities().isEmpty() &&
611  !job->sieveCapabilities().contains("vacation") ) {
612  KMessageBox::sorry( 0, i18n("Your server did not list \"vacation\" in "
613  "its list of supported Sieve extensions;\n"
614  "without it, KMail cannot install out-of-"
615  "office replies for you.\n"
616  "Please contact you system administrator.") );
617  emit result( false );
618  return;
619  }
620 
621  if ( !mDialog && !mCheckOnly )
622  mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, 0, false );
623 
624  TQString messageText = defaultMessageText();
625  int notificationInterval = defaultNotificationInterval();
626  TQStringList aliases = defaultMailAliases();
627  bool sendForSpam = defaultSendForSpam();
628  TQString domainName = defaultDomainName();
629  if ( !success ) active = false; // default to inactive
630 
631  if ( !mCheckOnly && ( !success || !parseScript( script, messageText, notificationInterval, aliases, sendForSpam, domainName ) ) )
632  KMessageBox::information( 0, i18n("Someone (probably you) changed the "
633  "vacation script on the server.\n"
634  "KMail is no longer able to determine "
635  "the parameters for the autoreplies.\n"
636  "Default values will be used." ) );
637 
638  mWasActive = active;
639  if ( mDialog ) {
640  mDialog->setActivateVacation( active );
641  mDialog->setMessageText( messageText );
642  mDialog->setNotificationInterval( notificationInterval );
643  mDialog->setMailAliases( aliases.join(", ") );
644  mDialog->setSendForSpam( sendForSpam );
645  mDialog->setDomainName( domainName );
646  mDialog->enableDomainAndSendForSpam( !GlobalSettings::allowOutOfOfficeUploadButNoSettings() );
647 
648  connect( mDialog, TQ_SIGNAL(okClicked()), TQ_SLOT(slotDialogOk()) );
649  connect( mDialog, TQ_SIGNAL(cancelClicked()), TQ_SLOT(slotDialogCancel()) );
650  connect( mDialog, TQ_SIGNAL(defaultClicked()), TQ_SLOT(slotDialogDefaults()) );
651 
652  mDialog->show();
653  }
654 
655  emit scriptActive( mWasActive );
656  if ( mCheckOnly && mWasActive ) {
657  if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n"
658  "Do you want to edit it?"), i18n("Out-of-office reply still active"),
659  KGuiItem( i18n( "Edit"), "edit" ), KGuiItem( i18n("Ignore"), "button_cancel" ) )
660  == KMessageBox::Yes ) {
661  kmkernel->getKMMainWidget()->slotEditVacation();
662  }
663  }
664  }
665 
666  void Vacation::slotDialogDefaults() {
667  if ( !mDialog )
668  return;
669  mDialog->setActivateVacation( true );
670  mDialog->setMessageText( defaultMessageText() );
671  mDialog->setNotificationInterval( defaultNotificationInterval() );
672  mDialog->setMailAliases( defaultMailAliases().join(", ") );
673  mDialog->setSendForSpam( defaultSendForSpam() );
674  mDialog->setDomainName( defaultDomainName() );
675  mDialog->setDomainCheck( false );
676  }
677 
678  void Vacation::slotDialogOk() {
679  kdDebug(5006) << "Vacation::slotDialogOk()" << endl;
680  // compose a new script:
681  const TQString script = composeScript( mDialog->messageText(),
682  mDialog->notificationInterval(),
683  mDialog->mailAliases(),
684  mDialog->sendForSpam(),
685  mDialog->domainName() );
686  const bool active = mDialog->activateVacation();
687  emit scriptActive( active );
688 
689  kdDebug(5006) << "script:" << endl << script << endl;
690 
691  // and commit the dialog's settings to the server:
692  mSieveJob = SieveJob::put( mUrl, script, active, mWasActive );
693  connect( mSieveJob, TQ_SIGNAL(gotScript(KMail::SieveJob*,bool,const TQString&,bool)),
694  active
695  ? TQ_SLOT(slotPutActiveResult(KMail::SieveJob*,bool))
696  : TQ_SLOT(slotPutInactiveResult(KMail::SieveJob*,bool)) );
697 
698  // destroy the dialog:
699  mDialog->delayedDestruct();
700  mDialog = 0;
701  }
702 
703  void Vacation::slotDialogCancel() {
704  kdDebug(5006) << "Vacation::slotDialogCancel()" << endl;
705  mDialog->delayedDestruct();
706  mDialog = 0;
707  emit result( false );
708  }
709 
710  void Vacation::slotPutActiveResult( SieveJob * job, bool success ) {
711  handlePutResult( job, success, true );
712  }
713 
714  void Vacation::slotPutInactiveResult( SieveJob * job, bool success ) {
715  handlePutResult( job, success, false );
716  }
717 
718  void Vacation::handlePutResult( SieveJob *, bool success, bool activated ) {
719  if ( success )
720  KMessageBox::information( 0, activated
721  ? i18n("Sieve script installed successfully on the server.\n"
722  "Out of Office reply is now active.")
723  : i18n("Sieve script installed successfully on the server.\n"
724  "Out of Office reply has been deactivated.") );
725 
726  kdDebug(5006) << "Vacation::handlePutResult( ???, " << success << ", ? )"
727  << endl;
728  mSieveJob = 0; // job deletes itself after returning from this slot!
729  emit result( success );
730  emit scriptActive( activated );
731  }
732 
733 
734 } // namespace KMail
735 
736 #include "vacation.moc"
The account manager is responsible for creating accounts of various types via the factory method crea...
const KMAccount * first() const
First account of the list.
const KMAccount * next() const
Next account of the list.
folderdiaquotatab.h
Definition: aboutdata.cpp:40