kmail

kmkernel.cpp
1 /* -*- mode: C++; c-file-style: "gnu" -*- */
2 #ifdef HAVE_CONFIG_H
3 #include <config.h>
4 #endif
5 
6 #include "config.h"
7 #include "kmkernel.h"
8 
9 #include <weaver.h>
10 #include <weaverlogger.h>
11 
12 #include "globalsettings.h"
13 #include "broadcaststatus.h"
14 using KPIM::BroadcastStatus;
15 #include "kmstartup.h"
16 #include "index.h"
17 #include "kmmainwin.h"
18 #include "composer.h"
19 #include "kmmsgpart.h"
20 #include "kmreadermainwin.h"
21 #include "kmfoldermgr.h"
22 #include "kmfoldercachedimap.h"
23 #include "kmacctcachedimap.h"
24 #include "kmfiltermgr.h"
25 #include "kmfilteraction.h"
26 #include "kmheaders.h"
27 #define REALLY_WANT_KMSENDER
28 #include "kmsender.h"
29 #undef REALLY_WANT_KMSENDER
30 #include "undostack.h"
31 #include "accountmanager.h"
33 #include <libkdepim/kfileio.h>
34 #include "kmversion.h"
35 #include "kmreaderwin.h"
36 #include "kmmainwidget.h"
37 #include "kmfoldertree.h"
38 #include "recentaddresses.h"
39 using KRecentAddress::RecentAddresses;
40 #include "kmmsgdict.h"
41 #include <libkpimidentities/identity.h>
42 #include <libkpimidentities/identitymanager.h>
43 #include "configuredialog.h"
44 #include "kmcommands.h"
45 #include "kmsystemtray.h"
46 #include "transportmanager.h"
47 #include "importarchivedialog.h"
48 
49 #include <kwin.h>
50 #include "kmailicalifaceimpl.h"
51 #include "mailserviceimpl.h"
52 using KMail::MailServiceImpl;
53 #include "mailcomposerIface.h"
54 #include "folderIface.h"
55 using KMail::FolderIface;
56 #include "jobscheduler.h"
57 #include "templateparser.h"
58 
59 #include <kapplication.h>
60 #include <kmessagebox.h>
61 #include <knotifyclient.h>
62 #include <kstaticdeleter.h>
63 #include <kstandarddirs.h>
64 #include <kconfig.h>
65 #include <kprogress.h>
66 #include <kpassivepopup.h>
67 #include <dcopclient.h>
68 #include <ksystemtray.h>
69 #include <kpgp.h>
70 #include <kdebug.h>
71 #include <kio/netaccess.h>
72 #include <kwallet.h>
73 using KWallet::Wallet;
74 #include "actionscheduler.h"
75 
76 #include <qutf7codec.h>
77 #include <tqvbox.h>
78 #include <tqdir.h>
79 #include <tqwidgetlist.h>
80 #include <tqobjectlist.h>
81 
82 #include <sys/types.h>
83 #include <dirent.h>
84 #include <sys/stat.h>
85 #include <unistd.h>
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <assert.h>
89 
90 #include <X11/Xlib.h>
91 #include <fixx11h.h>
92 #include <kcmdlineargs.h>
93 #include <kstartupinfo.h>
94 
95 KMKernel *KMKernel::mySelf = 0;
96 static bool s_askingToGoOnline = false;
97 
98 /********************************************************************/
99 /* Constructor and destructor */
100 /********************************************************************/
101 KMKernel::KMKernel (TQObject *parent, const char *name) :
102  DCOPObject("KMailIface"), TQObject(parent, name),
103  mIdentityManager(0), mConfigureDialog(0),
104  mContextMenuShown( false ), mWallet( 0 )
105 {
106  kdDebug(5006) << "KMKernel::KMKernel" << endl;
107  mySelf = this;
108  the_startingUp = true;
109  closed_by_user = true;
110  the_firstInstance = true;
111  the_msgIndex = 0;
112 
113  the_inboxFolder = 0;
114  the_outboxFolder = 0;
115  the_sentFolder = 0;
116  the_trashFolder = 0;
117  the_draftsFolder = 0;
118  the_templatesFolder = 0;
119 
120  the_folderMgr = 0;
121  the_imapFolderMgr = 0;
122  the_dimapFolderMgr = 0;
123  the_searchFolderMgr = 0;
124  the_undoStack = 0;
125  the_acctMgr = 0;
126  the_filterMgr = 0;
127  the_popFilterMgr = 0;
128  the_filterActionDict = 0;
129  the_msgSender = 0;
130  mWin = 0;
131  mMailCheckAborted = false;
132 
133  // make sure that we check for config updates before doing anything else
134  KMKernel::config();
135  // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it
136  // so better do it here, than in some code where changing the group of config()
137  // would be unexpected
138  GlobalSettings::self();
139 
140  // Set up DCOP interface
141  mICalIface = new KMailICalIfaceImpl();
142 
143  mJobScheduler = new JobScheduler( this );
144 
145  mXmlGuiInstance = 0;
146 
147  new Kpgp::Module();
148 
149  // register our own (libkdenetwork) utf-7 codec as long as TQt
150  // doesn't have it's own:
151  if ( !TQTextCodec::codecForName("utf-7") ) {
152  kdDebug(5006) << "No TQt-native utf-7 codec found; registering TQUtf7Codec from libkdenetwork" << endl;
153  (void) new TQUtf7Codec();
154  }
155 
156  // In the case of Japan. Japanese locale name is "eucjp" but
157  // The Japanese mail systems normally used "iso-2022-jp" of locale name.
158  // We want to change locale name from eucjp to iso-2022-jp at KMail only.
159  if ( TQCString(TQTextCodec::codecForLocale()->name()).lower() == "eucjp" )
160  {
161  netCodec = TQTextCodec::codecForName("jis7");
162  // TQTextCodec *cdc = TQTextCodec::codecForName("jis7");
163  // TQTextCodec::setCodecForLocale(cdc);
164  // KGlobal::locale()->setEncoding(cdc->mibEnum());
165  } else {
166  netCodec = TQTextCodec::codecForLocale();
167  }
168  mMailService = new MailServiceImpl();
169 
170  connectDCOPSignal( 0, 0, "kmailSelectFolder(TQString)",
171  "selectFolder(TQString)", false );
172 }
173 
174 KMKernel::~KMKernel ()
175 {
176  TQMap<KIO::Job*, putData>::Iterator it = mPutJobs.begin();
177  while ( it != mPutJobs.end() )
178  {
179  KIO::Job *job = it.key();
180  mPutJobs.remove( it );
181  job->kill();
182  it = mPutJobs.begin();
183  }
184 
185  delete mICalIface;
186  mICalIface = 0;
187  delete mMailService;
188  mMailService = 0;
189 
190  GlobalSettings::self()->writeConfig();
191  delete mWallet;
192  mWallet = 0;
193  mySelf = 0;
194  kdDebug(5006) << "KMKernel::~KMKernel" << endl;
195 }
196 
197 bool KMKernel::handleCommandLine( bool noArgsOpensReader )
198 {
199  TQString to, cc, bcc, subj, body;
200  QCStringList customHeaders;
201  KURL messageFile;
202  KURL::List attachURLs;
203  bool mailto = false;
204  bool checkMail = false;
205  bool viewOnly = false;
206  bool calledWithSession = false; // for ignoring '-session foo'
207 
208  // process args:
209  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
210  if (!args->getOption("subject").isNull())
211  {
212  subj = TQString::fromLocal8Bit(args->getOption("subject"));
213  // if kmail is called with 'kmail -session abc' then this doesn't mean
214  // that the user wants to send a message with subject "ession" but
215  // (most likely) that the user clicked on KMail's system tray applet
216  // which results in KMKernel::raise() calling "kmail kmail newInstance"
217  // via dcop which apparently executes the application with the original
218  // command line arguments and those include "-session ..." if
219  // kmail/kontact was restored by session management
220  if ( subj == "ession" ) {
221  subj = TQString();
222  calledWithSession = true;
223  }
224  else
225  mailto = true;
226  }
227 
228  if (!args->getOption("cc").isNull())
229  {
230  mailto = true;
231  cc = TQString::fromLocal8Bit(args->getOption("cc"));
232  }
233 
234  if (!args->getOption("bcc").isNull())
235  {
236  mailto = true;
237  bcc = TQString::fromLocal8Bit(args->getOption("bcc"));
238  }
239 
240  if (!args->getOption("msg").isNull())
241  {
242  mailto = true;
243  messageFile.setPath( TQString::fromLocal8Bit(args->getOption("msg")) );
244  }
245 
246  if (!args->getOption("body").isNull())
247  {
248  mailto = true;
249  body = TQString::fromLocal8Bit(args->getOption("body"));
250  }
251 
252  QCStringList attachList = args->getOptionList("attach");
253  if (!attachList.isEmpty())
254  {
255  mailto = true;
256  for ( QCStringList::Iterator it = attachList.begin() ; it != attachList.end() ; ++it )
257  if ( !(*it).isEmpty() )
258  attachURLs += KURL( TQString::fromLocal8Bit( *it ) );
259  }
260 
261  customHeaders = args->getOptionList("header");
262 
263  if (args->isSet("composer"))
264  mailto = true;
265 
266  if (args->isSet("check"))
267  checkMail = true;
268 
269  if ( !args->getOption( "view" ).isNull() ) {
270  viewOnly = true;
271  const TQString filename =
272  TQString::fromLocal8Bit( args->getOption( "view" ) );
273  messageFile = KURL::fromPathOrURL( filename );
274  if ( !messageFile.isValid() ) {
275  messageFile = KURL();
276  messageFile.setPath( filename );
277  }
278  }
279 
280  if ( !calledWithSession ) {
281  // only read additional command line arguments if kmail/kontact is
282  // not called with "-session foo"
283  for(int i= 0; i < args->count(); i++)
284  {
285  if (strncasecmp(args->arg(i),"mailto:",7)==0)
286  to += args->url(i).path() + ", ";
287  else {
288  TQString tmpArg = TQString::fromLocal8Bit( args->arg(i) );
289  KURL url( tmpArg );
290  if ( url.isValid() )
291  attachURLs += url;
292  else
293  to += tmpArg + ", ";
294  }
295  mailto = true;
296  }
297  if ( !to.isEmpty() ) {
298  // cut off the superfluous trailing ", "
299  to.truncate( to.length() - 2 );
300  }
301  }
302 
303  if ( !calledWithSession )
304  args->clear();
305 
306  if ( !noArgsOpensReader && !mailto && !checkMail && !viewOnly )
307  return false;
308 
309  if ( viewOnly )
310  viewMessage( messageFile );
311  else
312  action( mailto, checkMail, to, cc, bcc, subj, body, messageFile,
313  attachURLs, customHeaders );
314  return true;
315 }
316 
317 /********************************************************************/
318 /* DCOP-callable, and command line actions */
319 /********************************************************************/
320 void KMKernel::checkMail () //might create a new reader but won't show!!
321 {
322  if ( !kmkernel->askToGoOnline() )
323  return;
324  kmkernel->acctMgr()->checkMail(false);
325 }
326 
327 TQStringList KMKernel::accounts()
328 {
329  if( kmkernel->acctMgr() )
330  return kmkernel->acctMgr()->getAccounts();
331  return TQStringList();
332 }
333 
334 void KMKernel::checkAccount (const TQString &account) //might create a new reader but won't show!!
335 {
336  kdDebug(5006) << "KMKernel::checkMail called" << endl;
337 
338  KMAccount* acct = kmkernel->acctMgr()->findByName(account);
339  if (acct)
340  kmkernel->acctMgr()->singleCheckMail(acct, false);
341 }
342 
343 void KMKernel::loadProfile( const TQString& )
344 {
345 }
346 
347 void KMKernel::saveToProfile( const TQString& ) const
348 {
349 }
350 
351 void KMKernel::openReader( bool onlyCheck )
352 {
353  mWin = 0;
354  KMainWindow *ktmw = 0;
355  kdDebug(5006) << "KMKernel::openReader called" << endl;
356 
357  if (KMainWindow::memberList)
358  for (ktmw = KMainWindow::memberList->first(); ktmw;
359  ktmw = KMainWindow::memberList->next())
360  if (ktmw->isA("KMMainWin"))
361  break;
362 
363  bool activate;
364  if (ktmw) {
365  mWin = (KMMainWin *) ktmw;
366  activate = !onlyCheck; // existing window: only activate if not --check
367  if ( activate )
368  mWin->show();
369  } else {
370  mWin = new KMMainWin;
371  mWin->show();
372  activate = false; // new window: no explicit activation (#73591)
373  }
374 
375  if ( activate ) {
376  // Activate window - doing this instead of KWin::activateWindow(mWin->winId());
377  // so that it also works when called from KMailApplication::newInstance()
378 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY
379  KStartupInfo::setNewStartupId( mWin, kapp->startupId() );
380 #endif
381  }
382 }
383 
384 int KMKernel::openComposer (const TQString &to, const TQString &cc,
385  const TQString &bcc, const TQString &subject,
386  const TQString &body, int hidden,
387  const KURL &messageFile,
388  const KURL::List &attachURLs,
389  const QCStringList &customHeaders)
390 {
391  kdDebug(5006) << "KMKernel::openComposer called" << endl;
392  KMMessage *msg = new KMMessage;
393  msg->initHeader();
394  msg->setCharset("utf-8");
395  // tentatively decode to, cc and bcc because invokeMailer calls us with
396  // RFC 2047 encoded addresses in order to protect non-ASCII email addresses
397  if (!to.isEmpty())
398  msg->setTo( KMMsgBase::decodeRFC2047String( to.latin1() ) );
399  if (!cc.isEmpty())
400  msg->setCc( KMMsgBase::decodeRFC2047String( cc.latin1() ) );
401  if (!bcc.isEmpty())
402  msg->setBcc( KMMsgBase::decodeRFC2047String( bcc.latin1() ) );
403  if (!subject.isEmpty()) msg->setSubject(subject);
404  if (!messageFile.isEmpty() && messageFile.isLocalFile()) {
405  TQCString str = KPIM::kFileToString( messageFile.path(), true, false );
406  if( !str.isEmpty() ) {
407  msg->setBody( TQString(TQString::fromLocal8Bit( str )).utf8() );
408  } else {
409  TemplateParser parser( msg, TemplateParser::NewMessage );
410  parser.process( NULL, NULL );
411  }
412  }
413  else if (!body.isEmpty())
414  {
415  msg->setBody(body.utf8());
416  }
417  else
418  {
419  TemplateParser parser( msg, TemplateParser::NewMessage );
420  parser.process( NULL, NULL );
421  }
422 
423  if (!customHeaders.isEmpty())
424  {
425  for ( QCStringList::ConstIterator it = customHeaders.begin() ; it != customHeaders.end() ; ++it )
426  if ( !(*it).isEmpty() )
427  {
428  const int pos = (*it).find( ':' );
429  if ( pos > 0 )
430  {
431  TQCString header, value;
432  header = (*it).left( pos ).stripWhiteSpace();
433  value = (*it).mid( pos+1 ).stripWhiteSpace();
434  if ( !header.isEmpty() && !value.isEmpty() )
435  msg->setHeaderField( header, value );
436  }
437  }
438  }
439 
440  KMail::Composer * cWin = KMail::makeComposer( msg );
441  cWin->setCharset("", true);
442  for ( KURL::List::ConstIterator it = attachURLs.begin() ; it != attachURLs.end() ; ++it )
443  cWin->addAttach((*it));
444  if (hidden == 0) {
445  cWin->show();
446  // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
447  // so that it also works when called from KMailApplication::newInstance()
448 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY
449  KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
450 #endif
451  }
452  return 1;
453 }
454 
455 
456 int KMKernel::openComposer (const TQString &to, const TQString &cc,
457  const TQString &bcc, const TQString &subject,
458  const TQString &body, int hidden,
459  const TQString &attachName,
460  const TQCString &attachCte,
461  const TQCString &attachData,
462  const TQCString &attachType,
463  const TQCString &attachSubType,
464  const TQCString &attachParamAttr,
465  const TQString &attachParamValue,
466  const TQCString &attachContDisp )
467 {
468  kdDebug(5006) << "KMKernel::openComposer called (deprecated version)" << endl;
469 
470  return openComposer ( to, cc, bcc, subject, body, hidden,
471  attachName, attachCte, attachData,
472  attachType, attachSubType, attachParamAttr,
473  attachParamValue, attachContDisp, TQCString() );
474 }
475 
476 int KMKernel::openComposer (const TQString &to, const TQString &cc,
477  const TQString &bcc, const TQString &subject,
478  const TQString &body, int hidden,
479  const TQString &attachName,
480  const TQCString &attachCte,
481  const TQCString &attachData,
482  const TQCString &attachType,
483  const TQCString &attachSubType,
484  const TQCString &attachParamAttr,
485  const TQString &attachParamValue,
486  const TQCString &attachContDisp,
487  const TQCString &attachCharset )
488 {
489  kdDebug(5006) << "KMKernel::openComposer called (deprecated version)" << endl;
490  return openComposer ( to, cc, bcc, subject, body, hidden,
491  attachName, attachCte, attachData,
492  attachType, attachSubType, attachParamAttr,
493  attachParamValue, attachContDisp, attachCharset, 0 );
494 }
495 
496 int KMKernel::openComposer (const TQString &to, const TQString &cc,
497  const TQString &bcc, const TQString &subject,
498  const TQString &body, int hidden,
499  const TQString &attachName,
500  const TQCString &attachCte,
501  const TQCString &attachData,
502  const TQCString &attachType,
503  const TQCString &attachSubType,
504  const TQCString &attachParamAttr,
505  const TQString &attachParamValue,
506  const TQCString &attachContDisp,
507  const TQCString &attachCharset,
508  unsigned int identity )
509 {
510  kdDebug(5006) << "KMKernel::openComposer()" << endl;
511 
512  KMMessage *msg = new KMMessage;
513  KMMessagePart *msgPart = 0;
514  msg->initHeader();
515  msg->setCharset( "utf-8" );
516  if ( !cc.isEmpty() ) msg->setCc(cc);
517  if ( !bcc.isEmpty() ) msg->setBcc(bcc);
518  if ( !subject.isEmpty() ) msg->setSubject(subject);
519  if ( !to.isEmpty() ) msg->setTo(to);
520  if ( identity > 0 ) msg->setHeaderField( "X-KMail-Identity", TQString::number( identity ) );
521  if ( !body.isEmpty() ) {
522  msg->setBody(body.utf8());
523  } else {
524  TemplateParser parser( msg, TemplateParser::NewMessage );
525  parser.process( NULL, NULL );
526  }
527 
528  bool iCalAutoSend = false;
529  bool noWordWrap = false;
530  bool isICalInvitation = false;
531  KConfigGroup options( config(), "Groupware" );
532  if ( !attachData.isEmpty() ) {
533  isICalInvitation = attachName == "cal.ics" &&
534  attachType == "text" &&
535  attachSubType == "calendar" &&
536  attachParamAttr == "method";
537  // Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
538  if ( isICalInvitation && bcc.isEmpty() )
539  msg->setBcc( "" );
540  if ( isICalInvitation &&
541  GlobalSettings::self()->legacyBodyInvites() ) {
542  // KOrganizer invitation caught and to be sent as body instead
543  msg->setBody( attachData );
544  msg->setHeaderField( "Content-Type",
545  TQString( "text/calendar; method=%1; "
546  "charset=\"utf-8\"" ).
547  arg( attachParamValue ) );
548 
549  iCalAutoSend = true; // no point in editing raw ICAL
550  noWordWrap = true; // we shant word wrap inline invitations
551  } else {
552  // Just do what we're told to do
553  msgPart = new KMMessagePart;
554  msgPart->setName( attachName );
555  msgPart->setCteStr( attachCte );
556  msgPart->setBodyEncoded( attachData );
557  msgPart->setTypeStr( attachType );
558  msgPart->setSubtypeStr( attachSubType );
559  msgPart->setParameter( attachParamAttr, attachParamValue );
560  if( ! GlobalSettings::self()->exchangeCompatibleInvitations() ) {
561  msgPart->setContentDisposition( attachContDisp );
562  }
563  if( !attachCharset.isEmpty() ) {
564  // kdDebug(5006) << "KMKernel::openComposer set attachCharset to "
565  // << attachCharset << endl;
566  msgPart->setCharset( attachCharset );
567  }
568  // Don't show the composer window, if the automatic sending is checked
569  KConfigGroup options( config(), "Groupware" );
570  iCalAutoSend = options.readBoolEntry( "AutomaticSending", true );
571  }
572  }
573 
574  KMail::Composer * cWin = KMail::makeComposer();
575  cWin->setMsg( msg, !isICalInvitation /* mayAutoSign */ );
576  cWin->setSigningAndEncryptionDisabled( isICalInvitation
577  && GlobalSettings::self()->legacyBodyInvites() );
578  cWin->setAutoDelete( true );
579  if( noWordWrap )
580  cWin->disableWordWrap();
581  else
582  cWin->setCharset( "", true );
583  if ( msgPart )
584  cWin->addAttach(msgPart);
585 
586  if ( isICalInvitation ) {
587  cWin->disableRecipientNumberCheck();
588  cWin->disableForgottenAttachmentsCheck();
589  }
590 
591  if ( hidden == 0 && !iCalAutoSend ) {
592  cWin->show();
593  // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
594  // so that it also works when called from KMailApplication::newInstance()
595 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY
596  KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
597 #endif
598  } else {
599  cWin->setAutoDeleteWindow( true );
600  cWin->slotSendNow();
601  }
602 
603  return 1;
604 }
605 
606 void KMKernel::setDefaultTransport( const TQString & transport )
607 {
608  TQStringList availTransports = KMail::TransportManager::transportNames();
609  TQStringList::const_iterator it = availTransports.find( transport );
610  if ( it == availTransports.end() ) {
611  kdWarning() << "The transport you entered is not available" << endl;
612  return;
613  }
614  GlobalSettings::self()->setDefaultTransport( transport );
615 }
616 
617 DCOPRef KMKernel::openComposer(const TQString &to, const TQString &cc,
618  const TQString &bcc, const TQString &subject,
619  const TQString &body,bool hidden)
620 {
621  KMMessage *msg = new KMMessage;
622  msg->initHeader();
623  msg->setCharset("utf-8");
624  if (!cc.isEmpty()) msg->setCc(cc);
625  if (!bcc.isEmpty()) msg->setBcc(bcc);
626  if (!subject.isEmpty()) msg->setSubject(subject);
627  if (!to.isEmpty()) msg->setTo(to);
628  if (!body.isEmpty()) {
629  msg->setBody(body.utf8());
630  } else {
631  TemplateParser parser( msg, TemplateParser::NewMessage );
632  parser.process( NULL, NULL );
633  }
634 
635  KMail::Composer * cWin = KMail::makeComposer( msg );
636  cWin->setCharset("", true);
637  if (!hidden) {
638  cWin->show();
639  // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
640  // so that it also works when called from KMailApplication::newInstance()
641 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY
642  KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
643 #endif
644  }
645 
646  return DCOPRef( cWin->asMailComposerIFace() );
647 }
648 
649 DCOPRef KMKernel::newMessage(const TQString &to,
650  const TQString &cc,
651  const TQString &bcc,
652  bool hidden,
653  bool useFolderId,
654  const KURL & /*messageFile*/,
655  const KURL &attachURL)
656 {
657  KMail::Composer * win = 0;
658  KMMessage *msg = new KMMessage;
659  KMFolder *folder = NULL;
660  uint id;
661 
662  if ( useFolderId ) {
663  //create message with required folder identity
664  folder = currentFolder();
665  id = folder ? folder->identity() : 0;
666  msg->initHeader( id );
667  } else {
668  msg->initHeader();
669  }
670  msg->setCharset("utf-8");
671  //set basic headers
672  if (!to.isEmpty()) msg->setTo(to);
673  if (!cc.isEmpty()) msg->setCc(cc);
674  if (!bcc.isEmpty()) msg->setBcc(bcc);
675 
676  if ( useFolderId ) {
677  TemplateParser parser( msg, TemplateParser::NewMessage );
678  parser.process( NULL, folder );
679  win = makeComposer( msg, id );
680  } else {
681  TemplateParser parser( msg, TemplateParser::NewMessage );
682  parser.process( NULL, folder );
683  win = makeComposer( msg );
684  }
685 
686  //Add the attachment if we have one
687  if(!attachURL.isEmpty() && attachURL.isValid()) {
688  win->addAttach(attachURL);
689  }
690 
691  //only show window when required
692  if(!hidden) {
693  win->show();
694  }
695  return DCOPRef( win->asMailComposerIFace() );
696 }
697 
698 int KMKernel::viewMessage( const KURL & messageFile )
699 {
700  KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( 0, messageFile );
701 
702  openCommand->start();
703 
704  return 1;
705 }
706 
707 int KMKernel::sendCertificate( const TQString& to, const TQByteArray& certData )
708 {
709  KMMessage *msg = new KMMessage;
710  msg->initHeader();
711  msg->setCharset("utf-8");
712  msg->setSubject( i18n( "Certificate Signature Request" ) );
713  if (!to.isEmpty()) msg->setTo(to);
714  // ### Make this message customizable via KIOSK
715  msg->setBody( i18n( "Please create a certificate from attachment and return to sender." ).utf8() );
716 
717  KMail::Composer * cWin = KMail::makeComposer( msg );
718  cWin->setCharset("", true);
719  cWin->slotSetAlwaysSend( true );
720  if (!certData.isEmpty()) {
721  KMMessagePart *msgPart = new KMMessagePart;
722  msgPart->setName("smime.p10");
723  msgPart->setCteStr("base64");
724  msgPart->setBodyEncodedBinary(certData);
725  msgPart->setTypeStr("application");
726  msgPart->setSubtypeStr("pkcs10");
727  msgPart->setContentDisposition("attachment; filename=smime.p10");
728  cWin->addAttach(msgPart);
729  }
730 
731  cWin->show();
732  return 1;
733 }
734 
735 KMMsgStatus KMKernel::strToStatus(const TQString &flags)
736 {
737  KMMsgStatus status = 0;
738  if (!flags.isEmpty()) {
739  for (uint n = 0; n < flags.length() ; n++) {
740  switch (flags[n]) {
741  case 'N':
742  status |= KMMsgStatusNew;
743  break;
744  case 'U':
745  status |= KMMsgStatusUnread;
746  break;
747  case 'O':
748  status |= KMMsgStatusOld;
749  break;
750  case 'R':
751  status |= KMMsgStatusRead;
752  break;
753  case 'D':
754  status |= KMMsgStatusDeleted;
755  break;
756  case 'A':
757  status |= KMMsgStatusReplied;
758  break;
759  case 'F':
760  status |= KMMsgStatusForwarded;
761  break;
762  case 'Q':
763  status |= KMMsgStatusQueued;
764  break;
765  case 'K':
766  status |= KMMsgStatusTodo;
767  break;
768  case 'S':
769  status |= KMMsgStatusSent;
770  break;
771  case 'G':
772  status |= KMMsgStatusFlag;
773  break;
774  case 'W':
775  status |= KMMsgStatusWatched;
776  break;
777  case 'I':
778  status |= KMMsgStatusIgnored;
779  break;
780  case 'P':
781  status |= KMMsgStatusSpam;
782  break;
783  case 'H':
784  status |= KMMsgStatusHam;
785  break;
786  case 'T':
787  status |= KMMsgStatusHasAttach;
788  break;
789  case 'C':
790  status |= KMMsgStatusHasNoAttach;
791  break;
792  default:
793  break;
794  }
795  }
796  }
797  return status;
798 }
799 
800 int KMKernel::dcopAddMessage( const TQString & foldername, const TQString & msgUrlString,
801  const TQString & MsgStatusFlags)
802 {
803  return dcopAddMessage(foldername, KURL(msgUrlString), MsgStatusFlags);
804 }
805 
806 int KMKernel::dcopAddMessage( const TQString & foldername,const KURL & msgUrl,
807  const TQString & MsgStatusFlags)
808 {
809  kdDebug(5006) << "KMKernel::dcopAddMessage called" << endl;
810 
811  if ( foldername.isEmpty() || foldername.startsWith("."))
812  return -1;
813 
814  int retval;
815  bool readFolderMsgIds = false;
816  TQString _foldername = foldername.stripWhiteSpace();
817  _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences
818 
819  if ( foldername != mAddMessageLastFolder ) {
820  mAddMessageMsgIds.clear();
821  readFolderMsgIds = true;
822  mAddMessageLastFolder = foldername;
823  }
824 
825  if (!msgUrl.isEmpty() && msgUrl.isLocalFile()) {
826 
827  // This is a proposed change by Daniel Andor.
828  // He proposed to change from the fopen(blah)
829  // to a KPIM::kFileToString(blah).
830  // Although it assigns a TQString to a TQString,
831  // because of the implicit sharing this poses
832  // no memory or performance penalty.
833 
834  const TQCString messageText =
835  KPIM::kFileToString( msgUrl.path(), true, false );
836  if ( messageText.isEmpty() )
837  return -2;
838 
839  KMMessage *msg = new KMMessage();
840  msg->fromString( messageText );
841 
842  if (readFolderMsgIds) {
843  if ( foldername.contains("/")) {
844  TQString tmp_fname = "";
845  KMFolder *folder = NULL;
846  KMFolderDir *subfolder;
847  bool root = true;
848 
849  TQStringList subFList = TQStringList::split("/",_foldername,false);
850 
851  for ( TQStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
852  TQString _newFolder = *it;
853  if(_newFolder.startsWith(".")) return -1;
854 
855  if(root) {
856  folder = the_folderMgr->findOrCreate(*it, false);
857  if (folder) {
858  root = false;
859  tmp_fname = "/" + *it;
860  }
861  else return -1;
862  } else {
863  subfolder = folder->createChildFolder();
864  tmp_fname += "/" + *it;
865  if(!the_folderMgr->getFolderByURL( tmp_fname )) {
866  folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder);
867  }
868 
869  if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
870  }
871  }
872 
873  mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
874  if(!folder) return -1;
875 
876  } else {
877  mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
878  }
879  }
880 
881  if ( mAddMsgCurrentFolder ) {
882  if (readFolderMsgIds) {
883 
884  // OLD COMMENT:
885  // Try to determine if a message already exists in
886  // the folder. The message id that is searched for, is
887  // the subject line + the date. This should be quite
888  // unique. The change that a given date with a given
889  // subject is in the folder twice is very small.
890  // If the subject is empty, the fromStrip string
891  // is taken.
892 
893  // NEW COMMENT from Danny Kukawka (danny.kukawka@web.de):
894  // subject line + the date is only unique if the following
895  // return a correct unique value:
896  // time_t DT = mb->date();
897  // TQString dt = ctime(&DT);
898  // But if the datestring in the Header isn't RFC conform
899  // subject line + the date isn't unique.
900  //
901  // The only uique headerfield is the Message-ID. In some
902  // cases this could be empty. I then I use the
903  // subject line + dateStr .
904 
905  int i;
906 
907  mAddMsgCurrentFolder->open("dcopadd");
908  for( i=0; i<mAddMsgCurrentFolder->count(); i++) {
909  KMMsgBase *mb = mAddMsgCurrentFolder->getMsgBase(i);
910  TQString id = mb->msgIdMD5();
911  if ( id.isEmpty() ) {
912  id = mb->subject();
913  if ( id.isEmpty() )
914  id = mb->fromStrip();
915  if ( id.isEmpty() )
916  id = mb->toStrip();
917 
918  id += mb->dateStr();
919  }
920 
921  //fprintf(stderr,"%s\n",(const char *) id);
922  if ( !id.isEmpty() ) {
923  mAddMessageMsgIds.append(id);
924  }
925  }
926  mAddMsgCurrentFolder->close("dcopadd");
927  }
928 
929  TQString msgId = msg->msgIdMD5();
930  if ( msgId.isEmpty()) {
931  msgId = msg->subject();
932  if ( msgId.isEmpty() )
933  msgId = msg->fromStrip();
934  if ( msgId.isEmpty() )
935  msgId = msg->toStrip();
936 
937  msgId += msg->dateStr();
938  }
939 
940  int k = mAddMessageMsgIds.findIndex( msgId );
941  //fprintf(stderr,"find %s = %d\n",(const char *) msgId,k);
942 
943  if ( k == -1 ) {
944  if ( !msgId.isEmpty() ) {
945  mAddMessageMsgIds.append( msgId );
946  }
947 
948  if ( !MsgStatusFlags.isEmpty() ) {
949  KMMsgStatus status = strToStatus(MsgStatusFlags);
950  if (status) msg->setStatus(status);
951  }
952 
953  int index;
954  if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
955  mAddMsgCurrentFolder->unGetMsg( index );
956  retval = 1;
957  } else {
958  retval =- 2;
959  delete msg;
960  msg = 0;
961  }
962  } else {
963  //qDebug( "duplicate: " + msgId + "; subj: " + msg->subject() + ", from: " + msgId = msg->fromStrip());
964  retval = -4;
965  }
966  } else {
967  retval = -1;
968  }
969  } else {
970  retval = -2;
971  }
972  return retval;
973 }
974 
976 {
977  mAddMessageMsgIds.clear();
978  mAddMessageLastFolder = TQString();
979 }
980 
981 int KMKernel::dcopAddMessage_fastImport( const TQString & foldername,
982  const TQString & msgUrlString,
983  const TQString & MsgStatusFlags)
984 {
985  return dcopAddMessage_fastImport(foldername, KURL(msgUrlString), MsgStatusFlags);
986 }
987 
988 int KMKernel::dcopAddMessage_fastImport( const TQString & foldername,
989  const KURL & msgUrl,
990  const TQString & MsgStatusFlags)
991 {
992  // Use this function to import messages without
993  // search for already existing emails.
994  kdDebug(5006) << "KMKernel::dcopAddMessage_fastImport called" << endl;
995 
996  if ( foldername.isEmpty() || foldername.startsWith("."))
997  return -1;
998 
999  int retval;
1000  bool createNewFolder = false;
1001 
1002  TQString _foldername = foldername.stripWhiteSpace();
1003  _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences
1004 
1005  if ( foldername != mAddMessageLastFolder ) {
1006  createNewFolder = true;
1007  mAddMessageLastFolder = foldername;
1008  }
1009 
1010 
1011  if ( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) {
1012  const TQCString messageText =
1013  KPIM::kFileToString( msgUrl.path(), true, false );
1014  if ( messageText.isEmpty() )
1015  return -2;
1016 
1017  KMMessage *msg = new KMMessage();
1018  msg->fromString( messageText );
1019 
1020  if (createNewFolder) {
1021  if ( foldername.contains("/")) {
1022  TQString tmp_fname = "";
1023  KMFolder *folder = NULL;
1024  KMFolderDir *subfolder;
1025  bool root = true;
1026 
1027  TQStringList subFList = TQStringList::split("/",_foldername,false);
1028 
1029  for ( TQStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
1030  TQString _newFolder = *it;
1031  if(_newFolder.startsWith(".")) return -1;
1032 
1033  if(root) {
1034  folder = the_folderMgr->findOrCreate(*it, false);
1035  if (folder) {
1036  root = false;
1037  tmp_fname = "/" + *it;
1038  }
1039  else return -1;
1040  } else {
1041  subfolder = folder->createChildFolder();
1042  tmp_fname += "/" + *it;
1043  if(!the_folderMgr->getFolderByURL( tmp_fname )) {
1044  folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder);
1045  }
1046  if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
1047  }
1048  }
1049 
1050  mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
1051  if(!folder) return -1;
1052 
1053  } else {
1054  mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
1055  }
1056  }
1057 
1058  if ( mAddMsgCurrentFolder ) {
1059  int index;
1060 
1061  if( !MsgStatusFlags.isEmpty() ) {
1062  KMMsgStatus status = strToStatus(MsgStatusFlags);
1063  if (status) msg->setStatus(status);
1064  }
1065 
1066  if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
1067  mAddMsgCurrentFolder->unGetMsg( index );
1068  retval = 1;
1069  } else {
1070  retval =- 2;
1071  delete msg;
1072  msg = 0;
1073  }
1074  } else {
1075  retval = -1;
1076  }
1077  } else {
1078  retval = -2;
1079  }
1080 
1081  return retval;
1082 }
1083 
1084 void KMKernel::showImportArchiveDialog()
1085 {
1086  KMMainWidget *mainWidget = getKMMainWidget();
1087  KMail::ImportArchiveDialog *importDialog = new KMail::ImportArchiveDialog( mainWidget, WDestructiveClose );
1088  importDialog->setFolder( mainWidget->folderTree()->currentFolder() );
1089  importDialog->show();
1090 }
1091 
1092 TQStringList KMKernel::folderList() const
1093 {
1094  TQStringList folders;
1095  const TQString localPrefix = "/Local";
1096  folders << localPrefix;
1097  the_folderMgr->getFolderURLS( folders, localPrefix );
1098  the_imapFolderMgr->getFolderURLS( folders );
1099  the_dimapFolderMgr->getFolderURLS( folders );
1100  return folders;
1101 }
1102 
1103 DCOPRef KMKernel::getFolder( const TQString& vpath )
1104 {
1105  const TQString localPrefix = "/Local";
1106  if ( the_folderMgr->getFolderByURL( vpath ) )
1107  return DCOPRef( new FolderIface( vpath ) );
1108  else if ( vpath.startsWith( localPrefix ) &&
1109  the_folderMgr->getFolderByURL( vpath.mid( localPrefix.length() ) ) )
1110  return DCOPRef( new FolderIface( vpath.mid( localPrefix.length() ) ) );
1111  else if ( the_imapFolderMgr->getFolderByURL( vpath ) )
1112  return DCOPRef( new FolderIface( vpath ) );
1113  else if ( the_dimapFolderMgr->getFolderByURL( vpath ) )
1114  return DCOPRef( new FolderIface( vpath ) );
1115  return DCOPRef();
1116 }
1117 
1118 void KMKernel::raise()
1119 {
1120  DCOPRef kmail( "kmail", "kmail" );
1121  kmail.call( "newInstance" );
1122 }
1123 
1124 bool KMKernel::showMail( TQ_UINT32 serialNumber, TQString /* messageId */ )
1125 {
1126  KMMainWidget *mainWidget = 0;
1127  if (KMainWindow::memberList) {
1128  KMainWindow *win = 0;
1129  TQObjectList *l;
1130 
1131  // First look for a KMainWindow.
1132  for (win = KMainWindow::memberList->first(); win;
1133  win = KMainWindow::memberList->next()) {
1134  // Then look for a KMMainWidget.
1135  l = win->queryList("KMMainWidget");
1136  if (l && l->first()) {
1137  mainWidget = dynamic_cast<KMMainWidget *>(l->first());
1138  if (win->isActiveWindow())
1139  break;
1140  }
1141  }
1142  }
1143 
1144  if (mainWidget) {
1145  int idx = -1;
1146  KMFolder *folder = 0;
1147  KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
1148  if (!folder || (idx == -1))
1149  return false;
1150  KMFolderOpener openFolder(folder, "showmail");
1151  KMMsgBase *msgBase = folder->getMsgBase(idx);
1152  if (!msgBase)
1153  return false;
1154  bool unGet = !msgBase->isMessage();
1155  KMMessage *msg = folder->getMsg(idx);
1156 
1157  KMReaderMainWin *win = new KMReaderMainWin( false, false );
1158  KMMessage *newMessage = new KMMessage( *msg );
1159  newMessage->setParent( msg->parent() );
1160  newMessage->setMsgSerNum( msg->getMsgSerNum() );
1161  newMessage->setReadyToShow( true );
1162  win->showMsg( GlobalSettings::self()->overrideCharacterEncoding(), newMessage );
1163  win->show();
1164 
1165  if (unGet)
1166  folder->unGetMsg(idx);
1167  return true;
1168  }
1169 
1170  return false;
1171 }
1172 
1173 TQString KMKernel::getFrom( TQ_UINT32 serialNumber )
1174 {
1175  int idx = -1;
1176  KMFolder *folder = 0;
1177  KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
1178  if (!folder || (idx == -1))
1179  return TQString();
1180  KMFolderOpener openFolder(folder, "getFrom");
1181  KMMsgBase *msgBase = folder->getMsgBase(idx);
1182  if (!msgBase)
1183  return TQString();
1184  bool unGet = !msgBase->isMessage();
1185  KMMessage *msg = folder->getMsg(idx);
1186  TQString result = msg->from();
1187  if (unGet)
1188  folder->unGetMsg(idx);
1189  return result;
1190 }
1191 
1192 TQString KMKernel::debugScheduler()
1193 {
1194  TQString res = KMail::ActionScheduler::debug();
1195  return res;
1196 }
1197 
1198 TQString KMKernel::debugSernum( TQ_UINT32 serialNumber )
1199 {
1200  TQString res;
1201  if (serialNumber != 0) {
1202  int idx = -1;
1203  KMFolder *folder = 0;
1204  KMMsgBase *msg = 0;
1205  KMMsgDict::instance()->getLocation( serialNumber, &folder, &idx );
1206  // It's possible that the message has been deleted or moved into a
1207  // different folder
1208  if (folder && (idx != -1)) {
1209  // everything is ok
1210  KMFolderOpener openFolder(folder, "debugser");
1211  msg = folder->getMsgBase( idx );
1212  if (msg) {
1213  res.append( TQString( " subject %s,\n sender %s,\n date %s.\n" )
1214  .arg( msg->subject() )
1215  .arg( msg->fromStrip() )
1216  .arg( msg->dateStr() ) );
1217  } else {
1218  res.append( TQString( "Invalid serial number." ) );
1219  }
1220  } else {
1221  res.append( TQString( "Invalid serial number." ) );
1222  }
1223  }
1224  return res;
1225 }
1226 
1227 
1229 {
1230  mBackgroundTasksTimer->stop();
1231  mJobScheduler->pause();
1232 }
1233 
1235 {
1236  mJobScheduler->resume();
1237  mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true );
1238 }
1239 
1241 {
1242  if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
1243  return;
1244 
1245  GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Offline );
1246  BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended"));
1247  emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
1248 }
1249 
1251 {
1252  if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online )
1253  return;
1254 
1255  GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Online );
1256  BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed"));
1257  emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
1258 
1259  if ( kmkernel->msgSender()->sendImmediate() ) {
1260  kmkernel->msgSender()->sendQueued();
1261  }
1262 }
1263 
1265 {
1266  if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
1267  return true;
1268  else
1269  return false;
1270 }
1271 
1273 {
1274  // already asking means we are offline and need to wait anyhow
1275  if ( s_askingToGoOnline ) {
1276  return false;
1277  }
1278 
1279  if ( kmkernel->isOffline() ) {
1280  s_askingToGoOnline = true;
1281  int rc =
1282  KMessageBox::questionYesNo( KMKernel::self()->mainWin(),
1283  i18n("KMail is currently in offline mode. "
1284  "How do you want to proceed?"),
1285  i18n("Online/Offline"),
1286  i18n("Work Online"),
1287  i18n("Work Offline"));
1288 
1289  s_askingToGoOnline = false;
1290  if( rc == KMessageBox::No ) {
1291  return false;
1292  } else {
1293  kmkernel->resumeNetworkJobs();
1294  }
1295  }
1296  return true;
1297 }
1298 
1299 /********************************************************************/
1300 /* Kernel methods */
1301 /********************************************************************/
1302 
1303 void KMKernel::quit()
1304 {
1305  // Called when all windows are closed. Will take care of compacting,
1306  // sending... should handle session management too!!
1307 }
1308  /* TODO later:
1309  Asuming that:
1310  - msgsender is nonblocking
1311  (our own, TQSocketNotifier based. Pops up errors and sends signal
1312  senderFinished when done)
1313 
1314  o If we are getting mail, stop it (but dont lose something!)
1315  [Done already, see mailCheckAborted]
1316  o If we are sending mail, go on UNLESS this was called by SM,
1317  in which case stop ASAP that too (can we warn? should we continue
1318  on next start?)
1319  o If we are compacting, or expunging, go on UNLESS this was SM call.
1320  In that case stop compacting ASAP and continue on next start, before
1321  touching any folders. [Not needed anymore with CompactionJob]
1322 
1323  KMKernel::quit ()
1324  {
1325  SM call?
1326  if compacting, stop;
1327  if sending, stop;
1328  if receiving, stop;
1329  Windows will take care of themselves (composer should dump
1330  its messages, if any but not in deadMail)
1331  declare us ready for the End of the Session
1332 
1333  No, normal quit call
1334  All windows are off. Anything to do, should compact or sender sends?
1335  Yes, maybe put an icon in panel as a sign of life
1336  if sender sending, connect us to his finished slot, declare us ready
1337  for quit and wait for senderFinished
1338  if not, Folder manager, go compact sent-mail and outbox
1339 } (= call slotFinished())
1340 
1341 void KMKernel::slotSenderFinished()
1342 {
1343  good, Folder manager go compact sent-mail and outbox
1344  clean up stage1 (release folders and config, unregister from dcop)
1345  -- another kmail may start now ---
1346  kapp->quit();
1347 }
1348 */
1349 
1350 
1351 /********************************************************************/
1352 /* Init, Exit, and handler methods */
1353 /********************************************************************/
1354 void KMKernel::testDir(const char *_name)
1355 {
1356  TQString foldersPath = TQDir::homeDirPath() + TQString( _name );
1357  TQFileInfo info( foldersPath );
1358  if ( !info.exists() ) {
1359  if ( ::mkdir( TQFile::encodeName( foldersPath ) , S_IRWXU ) == -1 ) {
1360  KMessageBox::sorry(0, i18n("KMail could not create folder '%1';\n"
1361  "please make sure that you can view and "
1362  "modify the content of the folder '%2'.")
1363  .arg( foldersPath ).arg( TQDir::homeDirPath() ) );
1364  ::exit(-1);
1365  }
1366  }
1367  if ( !info.isDir() || !info.isReadable() || !info.isWritable() ) {
1368  KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
1369  "incorrect;\n"
1370  "please make sure that you can view and modify "
1371  "the content of this folder.")
1372  .arg( foldersPath ) );
1373  ::exit(-1);
1374  }
1375 }
1376 
1377 
1378 //-----------------------------------------------------------------------------
1379 // Open a composer for each message found in the dead.letter folder
1380 void KMKernel::recoverDeadLetters()
1381 {
1382  TQDir dir( localDataPath() + "autosave/cur" );
1383  if ( !dir.exists() ) {
1384  kdWarning(5006) << "Autosave directory " << dir.path() << " not found!" << endl;
1385  return;
1386  }
1387 
1388  const TQStringList entryList = dir.entryList( TQDir::Files | TQDir::NoSymLinks, TQDir::Unsorted );
1389  for ( unsigned int i = 0; i < entryList.size(); i++ ) {
1390  const TQString fileName = entryList[i];
1391  TQFile file( dir.path() + '/' + fileName );
1392  if ( !file.open( IO_ReadOnly ) ) {
1393  kdWarning(5006) << "Unable to open autosave file " << fileName << endl;
1394  continue;
1395  }
1396  const TQByteArray msgData = file.readAll();
1397  file.close();
1398 
1399  if ( msgData.isEmpty() ) {
1400  kdWarning(5006) << "autosave file " << fileName << " is empty!" << endl;
1401  continue;
1402  }
1403 
1404  KMMessage *msg = new KMMessage(); // Composer will take ownership
1405  msg->fromByteArray( msgData );
1406  KMail::Composer * win = KMail::makeComposer();
1407  win->setMsg( msg, false, false, true );
1408  win->setAutoSaveFilename( fileName );
1409  win->show();
1410  }
1411 }
1412 
1413 //-----------------------------------------------------------------------------
1414 void KMKernel::initFolders(KConfig* cfg)
1415 {
1416  TQString name;
1417 
1418  name = cfg->readEntry("inboxFolder");
1419 
1420  // Currently the folder manager cannot manage folders which are not
1421  // in the base folder directory.
1422  //if (name.isEmpty()) name = getenv("MAIL");
1423 
1424  if (name.isEmpty()) name = I18N_NOOP("inbox");
1425 
1426  the_inboxFolder = (KMFolder*)the_folderMgr->findOrCreate(name);
1427 
1428  if (the_inboxFolder->canAccess() != 0) {
1429  emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
1430  }
1431 
1432  the_inboxFolder->setSystemFolder(true);
1433  if ( the_inboxFolder->userWhoField().isEmpty() )
1434  the_inboxFolder->setUserWhoField( TQString() );
1435  // inboxFolder->open();
1436 
1437  the_outboxFolder = the_folderMgr->findOrCreate(cfg->readEntry("outboxFolder", I18N_NOOP("outbox")));
1438  if (the_outboxFolder->canAccess() != 0) {
1439  emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
1440  }
1441  the_outboxFolder->setNoChildren(true);
1442 
1443  the_outboxFolder->setSystemFolder(true);
1444  if ( the_outboxFolder->userWhoField().isEmpty() )
1445  the_outboxFolder->setUserWhoField( TQString() );
1446  /* Nuke the oubox's index file, to make sure that no ghost messages are in
1447  * it from a previous crash. Ghost messages happen in the outbox because it
1448  * the only folder where messages enter and leave within 5 seconds, which is
1449  * the leniency period for index invalidation. Since the number of mails in
1450  * this folder is expected to be very small, we can live with regenerating
1451  * the index on each start to be on the save side. */
1452  //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir )
1453  // unlink( TQFile::encodeName( the_outboxFolder->indexLocation() ) );
1454  the_outboxFolder->open("kmkernel");
1455 
1456  the_sentFolder = the_folderMgr->findOrCreate(cfg->readEntry("sentFolder", I18N_NOOP("sent-mail")));
1457  if (the_sentFolder->canAccess() != 0) {
1458  emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
1459  }
1460  the_sentFolder->setSystemFolder(true);
1461  if ( the_sentFolder->userWhoField().isEmpty() )
1462  the_sentFolder->setUserWhoField( TQString() );
1463  // the_sentFolder->open();
1464 
1465  the_trashFolder = the_folderMgr->findOrCreate(cfg->readEntry("trashFolder", I18N_NOOP("trash")));
1466  if (the_trashFolder->canAccess() != 0) {
1467  emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
1468  }
1469  the_trashFolder->setSystemFolder( true );
1470  if ( the_trashFolder->userWhoField().isEmpty() )
1471  the_trashFolder->setUserWhoField( TQString() );
1472  // the_trashFolder->open();
1473 
1474  the_draftsFolder = the_folderMgr->findOrCreate(cfg->readEntry("draftsFolder", I18N_NOOP("drafts")));
1475  if (the_draftsFolder->canAccess() != 0) {
1476  emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
1477  }
1478  the_draftsFolder->setSystemFolder( true );
1479  if ( the_draftsFolder->userWhoField().isEmpty() )
1480  the_draftsFolder->setUserWhoField( TQString() );
1481  the_draftsFolder->open("kmkernel");
1482 
1483  the_templatesFolder =
1484  the_folderMgr->findOrCreate( cfg->readEntry( "templatesFolder",
1485  I18N_NOOP("templates") ) );
1486  if ( the_templatesFolder->canAccess() != 0 ) {
1487  emergencyExit( i18n("You do not have read/write permission to your templates folder.") );
1488  }
1489  the_templatesFolder->setSystemFolder( true );
1490  if ( the_templatesFolder->userWhoField().isEmpty() )
1491  the_templatesFolder->setUserWhoField( TQString() );
1492  the_templatesFolder->open("kmkernel");
1493 }
1494 
1495 
1496 void KMKernel::init()
1497 {
1498  the_shuttingDown = false;
1499  the_server_is_ready = false;
1500 
1501  KConfig* cfg = KMKernel::config();
1502 
1503  TQDir dir;
1504 
1505  KConfigGroupSaver saver(cfg, "General");
1506  the_firstStart = cfg->readBoolEntry("first-start", true);
1507  cfg->writeEntry("first-start", false);
1508  the_previousVersion = cfg->readEntry("previous-version");
1509  cfg->writeEntry("previous-version", KMAIL_VERSION);
1510  TQString foldersPath = cfg->readPathEntry( "folders" );
1511  kdDebug(5006) << k_funcinfo << "foldersPath (from config): '" << foldersPath << "'" << endl;
1512 
1513  if ( foldersPath.isEmpty() ) {
1514  foldersPath = localDataPath() + "mail";
1515  if ( transferMail( foldersPath ) ) {
1516  cfg->writePathEntry( "folders", foldersPath );
1517  }
1518  kdDebug(5006) << k_funcinfo << "foldersPath (after transferMail): '" << foldersPath << "'" << endl;
1519  }
1520 
1521  // moved up here because KMMessage::stripOffPrefixes is used below
1523 
1524  the_undoStack = new UndoStack(20);
1525  the_folderMgr = new KMFolderMgr(foldersPath);
1526  the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
1527  the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
1528  recreateCorruptIndexFiles();
1529 
1530  the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir);
1531  KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
1532  if (lsf)
1533  the_searchFolderMgr->remove( lsf );
1534 
1535  the_acctMgr = new AccountManager();
1536  the_filterMgr = new KMFilterMgr();
1537  the_popFilterMgr = new KMFilterMgr(true);
1538  the_filterActionDict = new KMFilterActionDict;
1539 
1540  initFolders(cfg);
1541  the_acctMgr->readConfig();
1542  the_filterMgr->readConfig();
1543  the_popFilterMgr->readConfig();
1544  cleanupImapFolders();
1545 
1546  the_msgSender = new KMSender;
1547  the_server_is_ready = true;
1548  imProxy()->initialize();
1549  { // area for config group "Composer"
1550  KConfigGroupSaver saver(cfg, "Composer");
1551  if (cfg->readListEntry("pref-charsets").isEmpty())
1552  {
1553  cfg->writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
1554  }
1555  }
1556  readConfig();
1557  mICalIface->readConfig();
1558  // filterMgr->dump();
1559 #ifdef HAVE_INDEXLIB
1560  the_msgIndex = new KMMsgIndex(this); //create the indexer
1561 #else
1562  the_msgIndex = 0;
1563 #endif
1564 
1565 //#if 0
1566  the_weaver = new KPIM::ThreadWeaver::Weaver( this );
1567  the_weaverLogger = new KPIM::ThreadWeaver::WeaverThreadLogger(this);
1568  the_weaverLogger->attach (the_weaver);
1569 //#endif
1570 
1571  connect( the_folderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ),
1572  this, TQT_SIGNAL( folderRemoved(KMFolder*) ) );
1573  connect( the_dimapFolderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ),
1574  this, TQT_SIGNAL( folderRemoved(KMFolder*) ) );
1575  connect( the_imapFolderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ),
1576  this, TQT_SIGNAL( folderRemoved(KMFolder*) ) );
1577  connect( the_searchFolderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ),
1578  this, TQT_SIGNAL( folderRemoved(KMFolder*) ) );
1579 
1580  mBackgroundTasksTimer = new TQTimer( this, "mBackgroundTasksTimer" );
1581  connect( mBackgroundTasksTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotRunBackgroundTasks() ) );
1582 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
1583  mBackgroundTasksTimer->start( 10000, true ); // 10s, singleshot
1584 #else
1585  mBackgroundTasksTimer->start( 5 * 60000, true ); // 5 minutes, singleshot
1586 #endif
1587 
1588  TQTextCodec *codec;
1589  for ( int i = 0; ( codec = TQTextCodec::codecForIndex ( i ) ); i++ ) {
1590  const TQString asciiString( "azAZ19,.-#+!?=()&" );
1591  const TQCString encodedString = codec->fromUnicode( asciiString );
1592  if ( TQString::fromAscii( encodedString ) != asciiString ) {
1593  mNonAsciiCompatibleCodecs.append( codec );
1594  }
1595  }
1596 }
1597 
1598 bool KMKernel::isCodecAsciiCompatible( const TQTextCodec *codec )
1599 {
1600  return !mNonAsciiCompatibleCodecs.contains( codec );
1601 }
1602 
1603 void KMKernel::readConfig()
1604 {
1605  //Needed here, since this function is also called when the configuration
1606  //changes, and the static variables should be updated then - IOF
1608 }
1609 
1610 void KMKernel::cleanupImapFolders()
1611 {
1612  KMAccount *acct = 0;
1613  KMFolderNode *node = the_imapFolderMgr->dir().first();
1614  while (node)
1615  {
1616  if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
1617  && ( acct->type() == "imap" )) )
1618  {
1619  node = the_imapFolderMgr->dir().next();
1620  } else {
1621  KMFolder* folder = static_cast<KMFolder*>(node);
1622  // delete only local
1623  static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true );
1624  the_imapFolderMgr->remove(folder);
1625  node = the_imapFolderMgr->dir().first();
1626  }
1627  }
1628 
1629  node = the_dimapFolderMgr->dir().first();
1630  while (node)
1631  {
1632  if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
1633  && ( acct->type() == "cachedimap" )) )
1634  {
1635  node = the_dimapFolderMgr->dir().next();
1636  } else {
1637  the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
1638  node = the_dimapFolderMgr->dir().first();
1639  }
1640  }
1641 
1642  the_imapFolderMgr->quiet(true);
1643  for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
1644  {
1645  KMFolderImap *fld;
1646  KMAcctImap *imapAcct;
1647 
1648  if (acct->type() != "imap") continue;
1649  fld = static_cast<KMFolderImap*>(the_imapFolderMgr
1650  ->findOrCreate(TQString::number(acct->id()), false, acct->id())->storage());
1651  fld->setNoContent(true);
1652  fld->folder()->setLabel(acct->name());
1653  imapAcct = static_cast<KMAcctImap*>(acct);
1654  fld->setAccount(imapAcct);
1655  imapAcct->setImapFolder(fld);
1656  fld->close( "kernel", true );
1657  }
1658  the_imapFolderMgr->quiet(false);
1659 
1660  the_dimapFolderMgr->quiet( true );
1661  for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
1662  {
1663  KMFolderCachedImap *cfld = 0;
1664  KMAcctCachedImap *cachedImapAcct;
1665 
1666  if (acct->type() != "cachedimap" ) continue;
1667 
1668  KMFolder* fld = the_dimapFolderMgr->find(TQString::number(acct->id()));
1669  if( fld )
1670  cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
1671  if (cfld == 0) {
1672  // Folder doesn't exist yet
1673  cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(TQString::number(acct->id()),
1674  false, KMFolderTypeCachedImap)->storage());
1675  if (!cfld) {
1676  KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_dimapFolderMgr->basePath())));
1677  exit(-1);
1678  }
1679  cfld->folder()->setId( acct->id() );
1680  }
1681 
1682  cfld->setNoContent(true);
1683  cfld->folder()->setLabel(acct->name());
1684  cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
1685  cfld->setAccount(cachedImapAcct);
1686  cachedImapAcct->setImapFolder(cfld);
1687  cfld->close("kmkernel");
1688  }
1689  the_dimapFolderMgr->quiet( false );
1690 }
1691 
1692 void KMKernel::recreateCorruptIndexFiles()
1693 {
1694  TQValueList<TQGuardedPtr<KMFolder> > folders;
1695  TQValueList<KMFolderIndex*> foldersWithBrokenIndex;
1696  TQStringList strList;
1697  the_folderMgr->createFolderList( &strList, &folders );
1698  the_imapFolderMgr->createFolderList( &strList, &folders );
1699  the_dimapFolderMgr->createFolderList( &strList, &folders );
1700  for ( int i = 0; folders.at(i) != folders.end(); i++ ) {
1701  KMFolder * const folder = *folders.at(i);
1702  if ( !folder || folder->isDir() || folder->isOpened() )
1703  continue;
1704  KMFolderIndex * const index = dynamic_cast<KMFolderIndex*>( folder->storage() );
1705  if ( index && index->indexStatus() != KMFolderIndex::IndexOk ) {
1706  foldersWithBrokenIndex.append( index );
1707  }
1708  }
1709 
1710  if ( !foldersWithBrokenIndex.isEmpty() ) {
1711  TQStringList folderNames;
1712  for ( uint i = 0; i < foldersWithBrokenIndex.size(); i++ ) {
1713  folderNames << foldersWithBrokenIndex[i]->label();
1714  }
1715 
1716  KMessageBox::informationList( 0, i18n( "There is a problem with the mail index of the following "
1717  "folders, the indices will now be regenerated.\n"
1718  "This can happen because the index files are out of date, missing or corrupted.\n"
1719  "Contact your administrator if this happens frequently.\n"
1720  "Some information, like status flags, might get lost." ),
1721  folderNames, i18n( "Problem with mail indices" ) );
1722 
1723  for ( uint i = 0; i < foldersWithBrokenIndex.size(); i++ ) {
1724  foldersWithBrokenIndex[i]->silentlyRecreateIndex();
1725  }
1726  }
1727 }
1728 
1729 bool KMKernel::doSessionManagement()
1730 {
1731 
1732  // Do session management
1733  if (kapp->isRestored()){
1734  int n = 1;
1735  while (KMMainWin::canBeRestored(n)){
1736  //only restore main windows! (Matthias);
1737  if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
1738  (new KMMainWin)->restore(n);
1739  n++;
1740  }
1741  return true; // we were restored by SM
1742  }
1743  return false; // no, we were not restored
1744 }
1745 
1746 void KMKernel::closeAllKMailWindows()
1747 {
1748  if (!KMainWindow::memberList) return;
1749  TQPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
1750  KMainWindow *window = 0;
1751  while ((window = it.current()) != 0) {
1752  ++it;
1753  if (window->isA("KMMainWindow") ||
1754  window->inherits("KMail::SecondaryWindow"))
1755  window->close( true ); // close and delete the window
1756  }
1757 }
1758 
1759 void KMKernel::cleanup(void)
1760 {
1761  dumpDeadLetters();
1762  the_shuttingDown = true;
1763  closeAllKMailWindows();
1764 
1765  delete the_acctMgr;
1766  the_acctMgr = 0;
1767  delete the_filterMgr;
1768  the_filterMgr = 0;
1769  delete the_msgSender;
1770  the_msgSender = 0;
1771  delete the_filterActionDict;
1772  the_filterActionDict = 0;
1773  delete the_undoStack;
1774  the_undoStack = 0;
1775  delete the_popFilterMgr;
1776  the_popFilterMgr = 0;
1777 
1778 #if 0
1779  delete the_weaver;
1780  the_weaver = 0;
1781 #endif
1782 
1783  KConfig* config = KMKernel::config();
1784  KConfigGroupSaver saver(config, "General");
1785 
1786  if (the_trashFolder) {
1787 
1788  the_trashFolder->close("kmkernel", true);
1789 
1790  if (config->readBoolEntry("empty-trash-on-exit", true))
1791  {
1792  if ( the_trashFolder->count( true ) > 0 )
1793  the_trashFolder->expunge();
1794  }
1795  }
1796 
1797  mICalIface->cleanup();
1798 
1799  TQValueList<TQGuardedPtr<KMFolder> > folders;
1800  TQStringList strList;
1801  KMFolder *folder;
1802  the_folderMgr->createFolderList(&strList, &folders);
1803  for (int i = 0; folders.at(i) != folders.end(); i++)
1804  {
1805  folder = *folders.at(i);
1806  if (!folder || folder->isDir()) continue;
1807  folder->close("kmkernel", true);
1808  }
1809  strList.clear();
1810  folders.clear();
1811  the_searchFolderMgr->createFolderList(&strList, &folders);
1812  for (int i = 0; folders.at(i) != folders.end(); i++)
1813  {
1814  folder = *folders.at(i);
1815  if (!folder || folder->isDir()) continue;
1816  folder->close("kmkernel", true);
1817  }
1818 
1819  delete the_msgIndex;
1820  the_msgIndex = 0;
1821  delete the_folderMgr;
1822  the_folderMgr = 0;
1823  delete the_imapFolderMgr;
1824  the_imapFolderMgr = 0;
1825  delete the_dimapFolderMgr;
1826  the_dimapFolderMgr = 0;
1827  delete the_searchFolderMgr;
1828  the_searchFolderMgr = 0;
1829  delete mConfigureDialog;
1830  mConfigureDialog = 0;
1831  // do not delete, because mWin may point to an existing window
1832  // delete mWin;
1833  mWin = 0;
1834 
1835  if ( RecentAddresses::exists() )
1836  RecentAddresses::self( config )->save( config );
1837  config->sync();
1838 }
1839 
1840 bool KMKernel::transferMail( TQString & destinationDir )
1841 {
1842  TQString dir;
1843 
1844  // check whether the user has a ~/KMail folder
1845  TQFileInfo fi( TQDir::home(), "KMail" );
1846  if ( fi.exists() && fi.isDir() ) {
1847  dir = TQDir::homeDirPath() + "/KMail";
1848  // the following two lines can be removed once moving mail is reactivated
1849  destinationDir = dir;
1850  return true;
1851  }
1852 
1853  if ( dir.isEmpty() ) {
1854  // check whether the user has a ~/Mail folder
1855  fi.setFile( TQDir::home(), "Mail" );
1856  if ( fi.exists() && fi.isDir() &&
1857  TQFile::exists( TQDir::homeDirPath() + "/Mail/.inbox.index" ) ) {
1858  // there's a ~/Mail folder which seems to be used by KMail (because of the
1859  // index file)
1860  dir = TQDir::homeDirPath() + "/Mail";
1861  // the following two lines can be removed once moving mail is reactivated
1862  destinationDir = dir;
1863  return true;
1864  }
1865  }
1866 
1867  if ( dir.isEmpty() ) {
1868  return true; // there's no old mail folder
1869  }
1870 
1871 #if 0
1872  // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved)
1873  const TQString kmailName = kapp->aboutData()->programName();
1874  TQString msg;
1875  if ( KIO::NetAccess::exists( destinationDir, true, 0 ) ) {
1876  // if destinationDir exists, we need to warn about possible
1877  // overwriting of files. otherwise, we don't have to
1878  msg = i18n( "%1-%3 is the application name, %4-%7 are folder path",
1879  "<qt>The <i>%4</i> folder exists. "
1880  "%1 now uses the <i>%5</i> folder for "
1881  "its messages.<p>"
1882  "%2 can move the contents of <i>%6<i> into this folder for "
1883  "you, though this may replace any existing files with "
1884  "the same name in <i>%7</i>.<p>"
1885  "<strong>Would you like %3 to move the mail "
1886  "files now?</strong></qt>" )
1887  .arg( kmailName, kmailName, kmailName )
1888  .arg( dir, destinationDir, dir, destinationDir );
1889  } else {
1890  msg = i18n( "%1-%3 is the application name, %4-%6 are folder path",
1891  "<qt>The <i>%4</i> folder exists. "
1892  "%1 now uses the <i>%5</i> folder for "
1893  "its messages. %2 can move the contents of <i>%6</i> into "
1894  "this folder for you.<p>"
1895  "<strong>Would you like %3 to move the mail "
1896  "files now?</strong></qt>" )
1897  .arg( kmailName, kmailName, kmailName )
1898  .arg( dir, destinationDir, dir );
1899  }
1900  TQString title = i18n( "Migrate Mail Files?" );
1901  TQString buttonText = i18n( "Move" );
1902 
1903  if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) ==
1904  KMessageBox::No ) {
1905  destinationDir = dir;
1906  return true;
1907  }
1908 
1909  if ( !KIO::NetAccess::move( dir, destinationDir ) ) {
1910  kdDebug(5006) << k_funcinfo << "Moving " << dir << " to " << destinationDir << " failed: " << KIO::NetAccess::lastErrorString() << endl;
1911  kdDebug(5006) << k_funcinfo << "Deleting " << destinationDir << endl;
1912  KIO::NetAccess::del( destinationDir, 0 );
1913  destinationDir = dir;
1914  return false;
1915  }
1916 #endif
1917 
1918  return true;
1919 }
1920 
1921 
1922 void KMKernel::ungrabPtrKb(void)
1923 {
1924  if(!KMainWindow::memberList) return;
1925  TQWidget* widg = KMainWindow::memberList->first();
1926  Display* dpy;
1927 
1928  if (!widg) return;
1929  dpy = widg->x11Display();
1930  XUngrabKeyboard(dpy, CurrentTime);
1931  XUngrabPointer(dpy, CurrentTime);
1932 }
1933 
1934 
1935 // Message handler
1936 void KMKernel::kmailMsgHandler(TQtMsgType aType, const char* aMsg)
1937 {
1938  static int recurse=-1;
1939 
1940  recurse++;
1941 
1942  switch (aType)
1943  {
1944  case QtDebugMsg:
1945  case QtWarningMsg:
1946  kdDebug(5006) << aMsg << endl;
1947  break;
1948 
1949  case QtFatalMsg: // Hm, what about using kdFatal() here?
1950  ungrabPtrKb();
1951  kdDebug(5006) << kapp->caption() << " fatal error "
1952  << aMsg << endl;
1953  KMessageBox::error(0, aMsg);
1954  abort();
1955  }
1956 
1957  recurse--;
1958 }
1959 
1960 
1962 {
1963  if ( shuttingDown() )
1964  return; //All documents should be saved before shutting down is set!
1965 
1966  // make all composer windows autosave their contents
1967  if ( !KMainWindow::memberList )
1968  return;
1969 
1970  for ( TQPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it ) {
1971  if ( KMail::Composer * win = ::tqqt_cast<KMail::Composer*>( it.current() ) ) {
1972  win->autoSaveMessage();
1973  // saving the message has to be finished right here, we are called from a dtor,
1974  // therefore we have no chance to finish this later
1975  // yes, this is ugly and potentially dangerous, but the alternative is losing
1976  // currently composed messages...
1977  while ( win->isComposing() )
1978  tqApp->processEvents();
1979  }
1980  }
1981 }
1982 
1983 
1984 
1985 void KMKernel::action(bool mailto, bool check, const TQString &to,
1986  const TQString &cc, const TQString &bcc,
1987  const TQString &subj, const TQString &body,
1988  const KURL &messageFile,
1989  const KURL::List &attachURLs,
1990  const QCStringList &customHeaders)
1991 {
1992  if ( mailto )
1993  openComposer( to, cc, bcc, subj, body, 0, messageFile, attachURLs, customHeaders );
1994  else
1995  openReader( check );
1996 
1997  if ( check )
1998  checkMail();
1999  //Anything else?
2000 }
2001 
2002 void KMKernel::byteArrayToRemoteFile(const TQByteArray &aData, const KURL &aURL,
2003  bool overwrite)
2004 {
2005  // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
2006  KIO::Job *job = KIO::put(aURL, -1, overwrite, false);
2007  putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
2008  mPutJobs.insert(job, pd);
2009  connect(job, TQT_SIGNAL(dataReq(KIO::Job*,TQByteArray&)),
2010  TQT_SLOT(slotDataReq(KIO::Job*,TQByteArray&)));
2011  connect(job, TQT_SIGNAL(result(KIO::Job*)),
2012  TQT_SLOT(slotResult(KIO::Job*)));
2013 }
2014 
2015 void KMKernel::slotDataReq(KIO::Job *job, TQByteArray &data)
2016 {
2017  // send the data in 64 KB chunks
2018  const int MAX_CHUNK_SIZE = 64*1024;
2019  TQMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
2020  assert(it != mPutJobs.end());
2021  int remainingBytes = (*it).data.size() - (*it).offset;
2022  if( remainingBytes > MAX_CHUNK_SIZE )
2023  {
2024  // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
2025  data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
2026  (*it).offset += MAX_CHUNK_SIZE;
2027  //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes ("
2028  // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
2029  }
2030  else
2031  {
2032  // send the remaining bytes to the receiver (deep copy)
2033  data.duplicate( (*it).data.data() + (*it).offset, remainingBytes );
2034  (*it).data = TQByteArray();
2035  (*it).offset = 0;
2036  //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n";
2037  }
2038 }
2039 
2040 void KMKernel::slotResult(KIO::Job *job)
2041 {
2042  TQMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
2043  assert(it != mPutJobs.end());
2044  if (job->error())
2045  {
2046  if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
2047  {
2048  if (KMessageBox::warningContinueCancel(0,
2049  i18n("File %1 exists.\nDo you want to replace it?")
2050  .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace"))
2051  == KMessageBox::Continue)
2052  byteArrayToRemoteFile((*it).data, (*it).url, true);
2053  }
2054  else job->showErrorDialog();
2055  }
2056  mPutJobs.remove(it);
2057 }
2058 
2060  // ### FIXME: delay as promised in the kdoc of this function ;-)
2061  KMKernel::config()->sync();
2062 }
2063 
2064 void KMKernel::slotShowConfigurationDialog()
2065 {
2066  if( !mConfigureDialog ) {
2067  mConfigureDialog = new ConfigureDialog( 0, "configure", false );
2068  connect( mConfigureDialog, TQT_SIGNAL( configChanged() ),
2069  this, TQT_SLOT( slotConfigChanged() ) );
2070  }
2071 
2072  if( KMKernel::getKMMainWidget() == 0 )
2073  {
2074  // ensure that there is a main widget available
2075  // as parts of the configure dialog (identity) rely on this
2076  // and this slot can be called when there is only a KMComposeWin showing
2077  KMMainWin * win = new KMMainWin;
2078  win->show();
2079  }
2080  if( mConfigureDialog->isHidden() )
2081  {
2082  getKMMainWidget()->headers()->writeConfig();
2083  mConfigureDialog->show();
2084  }
2085  else
2086  mConfigureDialog->raise();
2087 }
2088 
2089 void KMKernel::slotConfigChanged()
2090 {
2091  readConfig();
2092  emit configChanged();
2093 }
2094 
2095 //-------------------------------------------------------------------------------
2096 //static
2098 {
2099  return locateLocal( "data", "kmail/" );
2100 }
2101 
2102 //-------------------------------------------------------------------------------
2103 
2105 {
2106  return !systemTrayApplets.isEmpty();
2107 }
2108 
2109 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet )
2110 {
2111  if ( systemTrayApplets.findIndex( applet ) == -1 ) {
2112  systemTrayApplets.append( applet );
2113  return true;
2114  }
2115  else
2116  return false;
2117 }
2118 
2119 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet )
2120 {
2121  TQValueList<const KSystemTray*>::iterator it =
2122  systemTrayApplets.find( applet );
2123  if ( it != systemTrayApplets.end() ) {
2124  systemTrayApplets.remove( it );
2125  return true;
2126  }
2127  else
2128  return false;
2129 }
2130 
2131 void KMKernel::emergencyExit( const TQString& reason )
2132 {
2133  TQString mesg;
2134  if ( reason.length() == 0 ) {
2135  mesg = i18n("KMail encountered a fatal error and will terminate now");
2136  } else {
2137  mesg = i18n("KMail encountered a fatal error and will "
2138  "terminate now.\nThe error was:\n%1").arg( reason );
2139  }
2140 
2141  kdWarning() << mesg << endl;
2142  KNotifyClient::userEvent( 0, "<qt>"+mesg+"</qt>", KNotifyClient::Messagebox, KNotifyClient::Error );
2143 
2144  ::exit(1);
2145 }
2146 
2151 {
2152  assert( folder );
2153  if ( folder == the_outboxFolder )
2154  return true;
2155  return folderIsDrafts( folder );
2156 }
2157 
2158 bool KMKernel::folderIsDrafts(const KMFolder * folder)
2159 {
2160  assert( folder );
2161  if ( folder == the_draftsFolder )
2162  return true;
2163 
2164  TQString idString = folder->idString();
2165  if ( idString.isEmpty() )
2166  return false;
2167 
2168  // search the identities if the folder matches the drafts-folder
2169  const KPIM::IdentityManager *im = identityManager();
2170  for ( KPIM::IdentityManager::ConstIterator it=im->begin(); it != im->end(); ++it )
2171  if ( (*it).drafts() == idString )
2172  return true;
2173  return false;
2174 }
2175 
2176 bool KMKernel::folderIsTemplates( const KMFolder *folder )
2177 {
2178  assert( folder );
2179  if ( folder == the_templatesFolder )
2180  return true;
2181 
2182  TQString idString = folder->idString();
2183  if ( idString.isEmpty() )
2184  return false;
2185 
2186  // search the identities if the folder matches the templates-folder
2187  const KPIM::IdentityManager *im = identityManager();
2188  for ( KPIM::IdentityManager::ConstIterator it=im->begin(); it != im->end(); ++it )
2189  if ( (*it).templates() == idString )
2190  return true;
2191  return false;
2192 }
2193 
2194 bool KMKernel::folderIsTrash(KMFolder * folder)
2195 {
2196  assert(folder);
2197  if (folder == the_trashFolder) return true;
2198  TQStringList actList = acctMgr()->getAccounts();
2199  TQStringList::Iterator it( actList.begin() );
2200  for( ; it != actList.end() ; ++it ) {
2201  KMAccount* act = acctMgr()->findByName( *it );
2202  if ( act && ( act->trash() == folder->idString() ) )
2203  return true;
2204  }
2205  return false;
2206 }
2207 
2209 {
2210  assert( folder );
2211  if ( folder == the_sentFolder )
2212  return true;
2213 
2214  TQString idString = folder->idString();
2215  if ( idString.isEmpty() ) return false;
2216 
2217  // search the identities if the folder matches the sent-folder
2218  const KPIM::IdentityManager * im = identityManager();
2219  for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
2220  if ( (*it).fcc() == idString ) return true;
2221  return false;
2222 }
2223 
2224 KPIM::IdentityManager * KMKernel::identityManager() {
2225  if ( !mIdentityManager ) {
2226  kdDebug(5006) << "instantating KPIM::IdentityManager" << endl;
2227  mIdentityManager = new KPIM::IdentityManager( false, this, "mIdentityManager" );
2228  }
2229  return mIdentityManager;
2230 }
2231 
2232 KMMsgIndex *KMKernel::msgIndex()
2233 {
2234  return the_msgIndex;
2235 }
2236 
2237 KMainWindow* KMKernel::mainWin()
2238 {
2239  if (KMainWindow::memberList) {
2240  KMainWindow *kmWin = 0;
2241 
2242  // First look for a KMMainWin.
2243  for (kmWin = KMainWindow::memberList->first(); kmWin;
2244  kmWin = KMainWindow::memberList->next())
2245  if (kmWin->isA("KMMainWin"))
2246  return kmWin;
2247 
2248  // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
2249  // case we are running inside Kontact) because we anyway only need
2250  // it for modal message boxes and for KNotify events.
2251  kmWin = KMainWindow::memberList->first();
2252  if ( kmWin )
2253  return kmWin;
2254  }
2255 
2256  // There's not a single KMainWindow. Create a KMMainWin.
2257  // This could happen if we want to pop up an error message
2258  // while we are still doing the startup wizard and no other
2259  // KMainWindow is running.
2260  mWin = new KMMainWin;
2261  return mWin;
2262 }
2263 
2264 
2269 {
2270  TQString title = i18n("Empty Trash");
2271  TQString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
2272  if (KMessageBox::warningContinueCancel(0, text, title,
2273  KStdGuiItem::cont(), "confirm_empty_trash")
2274  != KMessageBox::Continue)
2275  {
2276  return;
2277  }
2278 
2279  for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
2280  {
2281  KMFolder* trash = findFolderById(acct->trash());
2282  if (trash)
2283  {
2284  trash->expunge();
2285  }
2286  }
2287 }
2288 
2289 KConfig* KMKernel::config()
2290 {
2291  assert(mySelf);
2292  if (!mySelf->mConfig)
2293  {
2294  mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
2295  // Check that all updates have been run on the config file:
2296  KMail::checkConfigUpdates();
2297  }
2298  return mySelf->mConfig;
2299 }
2300 
2301 KMailICalIfaceImpl& KMKernel::iCalIface()
2302 {
2303  assert( mICalIface );
2304  return *mICalIface;
2305 }
2306 
2307 void KMKernel::selectFolder( TQString folderPath )
2308 {
2309  kdDebug(5006)<<"Selecting a folder "<<folderPath<<endl;
2310  const TQString localPrefix = "/Local";
2311  KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
2312  if ( !folder && folderPath.startsWith( localPrefix ) )
2313  folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
2314  if ( !folder )
2315  folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
2316  if ( !folder )
2317  folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
2318  Q_ASSERT( folder );
2319 
2320  KMMainWidget *widget = getKMMainWidget();
2321  Q_ASSERT( widget );
2322  if ( !widget )
2323  return;
2324 
2325  KMFolderTree *tree = widget->folderTree();
2326  tree->doFolderSelected( tree->indexOfFolder( folder ) );
2327  tree->ensureItemVisible( tree->indexOfFolder( folder ) );
2328 }
2329 
2331 {
2332  //This could definitely use a speadup
2333  TQWidgetList *l = kapp->topLevelWidgets();
2334  TQWidgetListIt it( *l );
2335  TQWidget *wid;
2336 
2337  while ( ( wid = it.current() ) != 0 ) {
2338  ++it;
2339  TQObjectList *l2 = wid->topLevelWidget()->queryList( "KMMainWidget" );
2340  if (l2 && l2->first()) {
2341  KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2->first() );
2342  Q_ASSERT( kmmw );
2343  delete l2;
2344  delete l;
2345  return kmmw;
2346  }
2347  delete l2;
2348  }
2349  delete l;
2350  return 0;
2351 }
2352 
2353 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
2354 {
2355  // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
2356  // a stable kmail release goes out with a nasty bug in CompactionJob...
2357  KConfigGroup generalGroup( config(), "General" );
2358 
2359  if ( generalGroup.readBoolEntry( "auto-expiring", true ) ) {
2360  the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2361  the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2362  the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2363  // the_searchFolderMgr: no expiry there
2364  }
2365 
2366  if ( generalGroup.readBoolEntry( "auto-compaction", true ) ) {
2367  the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
2368  // the_imapFolderMgr: no compaction
2369  the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
2370  // the_searchFolderMgr: no compaction
2371  }
2372 
2373 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
2374  mBackgroundTasksTimer->start( 60 * 1000, true ); // check again in 1 minute
2375 #else
2376  mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours
2377 #endif
2378 
2379 }
2380 
2381 void KMKernel::expireAllFoldersNow() // called by the GUI
2382 {
2383  the_folderMgr->expireAllFolders( true /*immediate*/ );
2384  the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
2385  the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
2386 }
2387 
2388 void KMKernel::compactAllFolders() // called by the GUI
2389 {
2390  the_folderMgr->compactAllFolders( true /*immediate*/ );
2391  //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
2392  the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
2393 }
2394 
2395 KMFolder* KMKernel::findFolderById( const TQString& idString )
2396 {
2397  KMFolder * folder = the_folderMgr->findIdString( idString );
2398  if ( !folder )
2399  folder = the_imapFolderMgr->findIdString( idString );
2400  if ( !folder )
2401  folder = the_dimapFolderMgr->findIdString( idString );
2402  if ( !folder )
2403  folder = the_searchFolderMgr->findIdString( idString );
2404  return folder;
2405 }
2406 
2407 ::KIMProxy* KMKernel::imProxy()
2408 {
2409  return KIMProxy::instance( kapp->dcopClient() );
2410 }
2411 
2413 {
2414  mMailCheckAborted = false;
2415 }
2416 
2418 {
2419  return mMailCheckAborted;
2420 }
2421 
2423 {
2424  mMailCheckAborted = true;
2425 }
2426 
2427 bool KMKernel::canQueryClose()
2428 {
2429  if ( KMMainWidget::mainWidgetList() &&
2430  KMMainWidget::mainWidgetList()->count() > 1 )
2431  return true;
2432  KMMainWidget *widget = getKMMainWidget();
2433  if ( !widget )
2434  return true;
2435  KMSystemTray* systray = widget->systray();
2436  if ( !systray || GlobalSettings::closeDespiteSystemTray() )
2437  return true;
2438  if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
2439  systray->hideKMail();
2440  return false;
2441  } else if ( ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) && ( systray->hasUnreadMail() )) {
2442  systray->show();
2443  systray->hideKMail();
2444  return false;
2445  }
2446  return true;
2447 }
2448 
2450 {
2451  mTimeOfLastMessageCountChange = ::time( 0 );
2452 }
2453 
2454 int KMKernel::timeOfLastMessageCountChange() const
2455 {
2456  return mTimeOfLastMessageCountChange;
2457 }
2458 
2459 Wallet *KMKernel::wallet() {
2460  static bool walletOpenFailed = false;
2461  if ( mWallet && mWallet->isOpen() )
2462  return mWallet;
2463 
2464  if ( !Wallet::isEnabled() || walletOpenFailed )
2465  return 0;
2466 
2467  // find an appropriate parent window for the wallet dialog
2468  WId window = 0;
2469  if ( tqApp->activeWindow() )
2470  window = tqApp->activeWindow()->winId();
2471  else if ( getKMMainWidget() )
2472  window = getKMMainWidget()->topLevelWidget()->winId();
2473 
2474  delete mWallet;
2475  mWallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
2476 
2477  if ( !mWallet ) {
2478  walletOpenFailed = true;
2479  return 0;
2480  }
2481 
2482  if ( !mWallet->hasFolder( "kmail" ) )
2483  mWallet->createFolder( "kmail" );
2484  mWallet->setFolder( "kmail" );
2485  return mWallet;
2486 }
2487 
2488 TQValueList< TQGuardedPtr<KMFolder> > KMKernel::allFolders()
2489 {
2490  TQStringList names;
2491  TQValueList<TQGuardedPtr<KMFolder> > folders;
2492  folderMgr()->createFolderList(&names, &folders);
2493  imapFolderMgr()->createFolderList(&names, &folders);
2494  dimapFolderMgr()->createFolderList(&names, &folders);
2495  searchFolderMgr()->createFolderList(&names, &folders);
2496 
2497  return folders;
2498 }
2499 
2500 KMFolder *KMKernel::currentFolder() {
2501  KMMainWidget *widget = getKMMainWidget();
2502  KMFolder *folder = 0;
2503  if ( widget && widget->folderTree() ) {
2504  folder = widget->folderTree()->currentFolder();
2505  }
2506  return folder;
2507 }
2508 
2509 // can't be inline, since KMSender isn't known to implement
2510 // KMail::MessageSender outside this .cpp file
2511 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; }
2512 
2513 #include "kmkernel.moc"