kcmshell renamed to kcmshell4 to fix co-installability between kdelibs3 and kdebase4...
[kdepim.git] / kmail / kmkernel.cpp
blob2bb33d65eb98cb5b7280f86f928705f589d9f649
1 /* -*- mode: C++; c-file-style: "gnu" -*- */
3 #include <config-kmail.h>
4 #include "kmkernel.h"
6 #include "globalsettings.h"
7 #include "broadcaststatus.h"
8 using KPIM::BroadcastStatus;
9 #include "kmstartup.h"
10 #include "kmmainwin.h"
11 #include "composer.h"
12 #include "kmmsgpart.h"
13 #include "kmreadermainwin.h"
14 #include "kmfoldermgr.h"
15 #include "kmfoldercachedimap.h"
16 #include "kmacctcachedimap.h"
17 #include "kmfiltermgr.h"
18 #include "kmfilteraction.h"
19 #define REALLY_WANT_KMSENDER
20 #include "kmsender.h"
21 #undef REALLY_WANT_KMSENDER
22 #include "undostack.h"
23 #include "accountmanager.h"
24 using KMail::AccountManager;
25 #include <kpimutils/kfileio.h>
26 #include "kmversion.h"
27 #include "kmreaderwin.h"
28 #include "kmmainwidget.h"
29 #include "kmfoldertree.h"
30 #include "recentaddresses.h"
31 using KPIM::RecentAddresses;
32 #include "kmmsgdict.h"
33 #include <kpimidentities/identity.h>
34 #include <kpimidentities/identitymanager.h>
35 #include "configuredialog.h"
36 #include "kmcommands.h"
37 #include "kmsystemtray.h"
39 #include <mailtransport/transport.h>
40 #include <mailtransport/transportmanager.h>
42 #include <kwindowsystem.h>
43 #include "kmailicalifaceimpl.h"
44 #include "mailserviceimpl.h"
45 using KMail::MailServiceImpl;
46 #include "jobscheduler.h"
47 #include "templateparser.h"
48 using KMail::TemplateParser;
50 #include <kmessagebox.h>
51 #include <knotification.h>
52 #include <kstandarddirs.h>
53 #include <kconfig.h>
54 #include <kpassivepopup.h>
55 #include <kapplication.h>
56 #include <ksystemtrayicon.h>
57 #include <kconfiggroup.h>
58 #include <libkpgp/kpgp.h>
59 #include <kdebug.h>
60 #include <kio/netaccess.h>
61 #include <kwallet.h>
62 using KWallet::Wallet;
63 #include "actionscheduler.h"
65 #include <QByteArray>
66 #include <QDir>
67 #include <QList>
68 #include <QObject>
69 #include <QWidget>
71 #include <sys/types.h>
72 #include <dirent.h>
73 #include <sys/stat.h>
74 #include <unistd.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <assert.h>
79 #include <kcmdlineargs.h>
80 #include <kstartupinfo.h>
81 #include <kmailadaptor.h>
82 #include "kmailinterface.h"
83 KMKernel *KMKernel::mySelf = 0;
84 #include "folderadaptor.h"
85 #include "kmail_util.h"
87 /********************************************************************/
88 /* Constructor and destructor */
89 /********************************************************************/
90 KMKernel::KMKernel (QObject *parent, const char *name) :
91 QObject(parent),
92 mIdentityManager(0), mConfigureDialog(0), mICalIface(0), mMailService(0),
93 mContextMenuShown( false ), mWallet( 0 )
95 kDebug(5006);
96 setObjectName( name );
97 mySelf = this;
98 the_startingUp = true;
99 closed_by_user = true;
100 the_firstInstance = true;
102 the_inboxFolder = 0;
103 the_outboxFolder = 0;
104 the_sentFolder = 0;
105 the_trashFolder = 0;
106 the_draftsFolder = 0;
107 the_templatesFolder = 0;
109 the_folderMgr = 0;
110 the_imapFolderMgr = 0;
111 the_dimapFolderMgr = 0;
112 the_searchFolderMgr = 0;
113 the_undoStack = 0;
114 the_acctMgr = 0;
115 the_filterMgr = 0;
116 the_popFilterMgr = 0;
117 the_filterActionDict = 0;
118 the_msgSender = 0;
119 the_msgTagMgr = 0;
120 mWin = 0;
121 mMailCheckAborted = false;
122 folderAdaptor=0;
123 // make sure that we check for config updates before doing anything else
124 KMKernel::config();
125 // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it
126 // so better do it here, than in some code where changing the group of config()
127 // would be unexpected
128 GlobalSettings::self();
130 mJobScheduler = new JobScheduler( this );
132 mXmlGuiInstance = KComponentData();
134 new Kpgp::Module();
136 // In the case of Japan. Japanese locale name is "eucjp" but
137 // The Japanese mail systems normally used "iso-2022-jp" of locale name.
138 // We want to change locale name from eucjp to iso-2022-jp at KMail only.
139 if ( QByteArray(QTextCodec::codecForLocale()->name()).toLower() == "eucjp" )
141 netCodec = QTextCodec::codecForName("jis7");
142 // QTextCodec *cdc = QTextCodec::codecForName("jis7");
143 // QTextCodec::setCodecForLocale(cdc);
144 // KGlobal::locale()->setEncoding(cdc->mibEnum());
145 } else {
146 netCodec = QTextCodec::codecForLocale();
149 connect( MailTransport::TransportManager::self(),
150 SIGNAL(transportRemoved(int,QString)),
151 SLOT(transportRemoved(int,QString)) );
152 connect( MailTransport::TransportManager::self(),
153 SIGNAL(transportRenamed(int,QString,QString)),
154 SLOT(transportRenamed(int,QString,QString)) );
157 KMKernel::~KMKernel ()
159 QMap<KIO::Job*, putData>::Iterator it = mPutJobs.begin();
160 while ( it != mPutJobs.end() )
162 KIO::Job *job = it.key();
163 mPutJobs.erase( it );
164 job->kill();
165 it = mPutJobs.begin();
168 delete mICalIface;
169 mICalIface = 0;
170 delete mMailService;
171 mMailService = 0;
173 GlobalSettings::self()->writeConfig();
174 delete mWallet;
175 mWallet = 0;
176 mySelf = 0;
177 kDebug(5006);
180 void KMKernel::setupDBus()
182 (void) new KmailAdaptor( this );
183 QDBusConnection::sessionBus().registerObject("/KMail", this);
184 mICalIface = new KMailICalIfaceImpl();
185 mICalIface->readConfig();
186 mMailService = new MailServiceImpl();
189 bool KMKernel::handleCommandLine( bool noArgsOpensReader )
191 QString to, cc, bcc, subj, body;
192 QStringList customHeaders;
193 KUrl messageFile;
194 KUrl::List attachURLs;
195 bool mailto = false;
196 bool checkMail = false;
197 bool viewOnly = false;
198 bool calledWithSession = false; // for ignoring '-session foo'
200 // process args:
201 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
202 if (args->isSet("subject"))
204 subj = args->getOption("subject");
205 // if kmail is called with 'kmail -session abc' then this doesn't mean
206 // that the user wants to send a message with subject "ession" but
207 // (most likely) that the user clicked on KMail's system tray applet
208 // which results in KMKernel::raise() calling "kmail kmail newInstance"
209 // via dcop which apparently executes the application with the original
210 // command line arguments and those include "-session ..." if
211 // kmail/kontact was restored by session management
212 if ( subj == "ession" ) {
213 subj.clear();
214 calledWithSession = true;
216 else
217 mailto = true;
220 if (args->isSet("cc"))
222 mailto = true;
223 cc = args->getOption("cc");
226 if (args->isSet("bcc"))
228 mailto = true;
229 bcc = args->getOption("bcc");
232 if (args->isSet("msg"))
234 mailto = true;
235 messageFile.setPath( args->getOption("msg") );
238 if (args->isSet("body"))
240 mailto = true;
241 body = args->getOption("body");
244 QStringList attachList = args->getOptionList("attach");
245 if (!attachList.isEmpty())
247 mailto = true;
248 for ( QStringList::Iterator it = attachList.begin() ; it != attachList.end() ; ++it )
249 if ( !(*it).isEmpty() )
250 attachURLs += KUrl( *it );
253 customHeaders = args->getOptionList("header");
255 if (args->isSet("composer"))
256 mailto = true;
258 if (args->isSet("check"))
259 checkMail = true;
261 if ( args->isSet( "view" ) ) {
262 viewOnly = true;
263 const QString filename =
264 args->getOption( "view" );
265 messageFile = KUrl( filename );
266 if ( !messageFile.isValid() ) {
267 messageFile = KUrl();
268 messageFile.setPath( filename );
272 if ( !calledWithSession ) {
273 // only read additional command line arguments if kmail/kontact is
274 // not called with "-session foo"
275 for(int i= 0; i < args->count(); i++)
277 if (args->arg(i).startsWith("mailto:", Qt::CaseInsensitive))
278 to += args->url(i).path() + ", ";
279 else {
280 QString tmpArg = args->arg(i);
281 KUrl url( tmpArg );
282 if ( url.isValid() )
283 attachURLs += url;
284 else
285 to += tmpArg + ", ";
287 mailto = true;
289 if ( !to.isEmpty() ) {
290 // cut off the superfluous trailing ", "
291 to.truncate( to.length() - 2 );
295 if ( !calledWithSession )
296 args->clear();
298 if ( !noArgsOpensReader && !mailto && !checkMail && !viewOnly )
299 return false;
301 if ( viewOnly )
302 viewMessage( messageFile );
303 else
304 action( mailto, checkMail, to, cc, bcc, subj, body, messageFile,
305 attachURLs, customHeaders );
306 return true;
309 /********************************************************************/
310 /* DCOP-callable, and command line actions */
311 /********************************************************************/
312 void KMKernel::checkMail () //might create a new reader but won't show!!
314 kmkernel->acctMgr()->checkMail(false);
317 QStringList KMKernel::accounts()
319 return kmkernel->acctMgr()->getAccounts();
322 void KMKernel::checkAccount (const QString &account) //might create a new reader but won't show!!
324 kDebug(5006) <<"KMKernel::checkMail called";
326 KMAccount* acct = kmkernel->acctMgr()->findByName(account);
327 if (acct)
328 kmkernel->acctMgr()->singleCheckMail(acct, false);
331 void KMKernel::openReader( bool onlyCheck )
333 mWin = 0;
334 KMainWindow *ktmw = 0;
335 kDebug(5006) <<"KMKernel::openReader called";
337 foreach ( KMainWindow *window, KMainWindow::memberList() )
339 if ( ::qobject_cast<KMMainWin *>( window ) )
341 ktmw = window;
342 break;
346 bool activate;
347 if (ktmw) {
348 mWin = (KMMainWin *) ktmw;
349 activate = !onlyCheck; // existing window: only activate if not --check
350 if ( activate )
351 mWin->show();
353 else {
354 mWin = new KMMainWin;
355 mWin->show();
356 activate = false; // new window: no explicit activation (#73591)
359 if ( activate ) {
360 // Activate window - doing this instead of KWindowSystem::activateWindow(mWin->winId());
361 // so that it also works when called from KMailApplication::newInstance()
362 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
363 KStartupInfo::setNewStartupId( mWin, kapp->startupId() );
364 #endif
368 int KMKernel::openComposer( const QString &to, const QString &cc,
369 const QString &bcc, const QString &subject,
370 const QString &body, int hidden,
371 const KUrl &messageFile,
372 const KUrl::List &attachURLs,
373 const QStringList &customHeaders )
375 kDebug(5006) <<"KMKernel::openComposer called";
376 KMMessage *msg = new KMMessage;
377 msg->initHeader();
378 msg->setCharset("utf-8");
379 // tentatively decode to, cc and bcc because invokeMailer calls us with
380 // RFC 2047 encoded addresses in order to protect non-ASCII email addresses
381 if (!to.isEmpty())
382 msg->setTo( KMMsgBase::decodeRFC2047String( to.toLatin1() ) );
383 if (!cc.isEmpty())
384 msg->setCc( KMMsgBase::decodeRFC2047String( cc.toLatin1() ) );
385 if (!bcc.isEmpty())
386 msg->setBcc( KMMsgBase::decodeRFC2047String( bcc.toLatin1() ) );
387 if (!subject.isEmpty()) msg->setSubject(subject);
388 if (!messageFile.isEmpty() && messageFile.isLocalFile()) {
389 QByteArray str = KPIMUtils::kFileToByteArray( messageFile.path(), true, false );
390 if( !str.isEmpty() ) {
391 msg->setBody( QString::fromLocal8Bit( str.data(), str.size() ).toUtf8() );
393 else {
394 TemplateParser parser( msg, TemplateParser::NewMessage,
395 QString(), false, false, false );
396 parser.process( NULL, NULL );
399 else if (!body.isEmpty()) {
400 msg->setBody(body.toUtf8());
402 else {
403 TemplateParser parser( msg, TemplateParser::NewMessage,
404 QString(), false, false, false );
405 parser.process( NULL, NULL );
408 if (!customHeaders.isEmpty())
410 for ( QStringList::ConstIterator it = customHeaders.begin() ; it != customHeaders.end() ; ++it )
411 if ( !(*it).isEmpty() )
413 const int pos = (*it).find( ':' );
414 if ( pos > 0 )
416 QString header = (*it).left( pos ).trimmed();
417 QString value = (*it).mid( pos+1 ).trimmed();
418 if ( !header.isEmpty() && !value.isEmpty() )
419 msg->setHeaderField( header.toUtf8(), value );
424 KMail::Composer * cWin = KMail::makeComposer( msg );
425 cWin->setCharset("", true);
426 for ( KUrl::List::ConstIterator it = attachURLs.begin() ; it != attachURLs.end() ; ++it )
427 cWin->addAttach((*it));
428 if (hidden == 0) {
429 cWin->show();
430 // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
431 // so that it also works when called from KMailApplication::newInstance()
432 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
433 KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
434 #endif
436 return 1;
439 int KMKernel::openComposer (const QString &to, const QString &cc,
440 const QString &bcc, const QString &subject,
441 const QString &body, int hidden,
442 const QString &attachName,
443 const QByteArray &attachCte,
444 const QByteArray &attachData,
445 const QByteArray &attachType,
446 const QByteArray &attachSubType,
447 const QByteArray &attachParamAttr,
448 const QString &attachParamValue,
449 const QByteArray &attachContDisp,
450 const QByteArray &attachCharset )
452 kDebug(5006) <<"KMKernel::openComposer()";
454 KMMessage *msg = new KMMessage;
455 KMMessagePart *msgPart = 0;
456 msg->initHeader();
457 msg->setCharset( "utf-8" );
458 if ( !cc.isEmpty() ) msg->setCc(cc);
459 if ( !bcc.isEmpty() ) msg->setBcc(bcc);
460 if ( !subject.isEmpty() ) msg->setSubject(subject);
461 if ( !to.isEmpty() ) msg->setTo(to);
462 if ( !body.isEmpty() ) {
463 msg->setBody(body.toUtf8());
464 } else {
465 TemplateParser parser( msg, TemplateParser::NewMessage,
466 QString(), false, false, false );
467 parser.process( NULL, NULL );
470 bool iCalAutoSend = false;
471 bool noWordWrap = false;
472 bool isICalInvitation = false;
473 KConfigGroup options( config(), "Groupware" );
474 if ( !attachData.isEmpty() ) {
475 isICalInvitation = attachName == "cal.ics" &&
476 attachType == "text" &&
477 attachSubType == "calendar" &&
478 attachParamAttr == "method";
479 // Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
480 if ( isICalInvitation && bcc.isEmpty() )
481 msg->setBcc( "" );
482 if ( isICalInvitation &&
483 GlobalSettings::self()->legacyBodyInvites() ) {
484 // KOrganizer invitation caught and to be sent as body instead
485 msg->setBody( attachData );
486 msg->setHeaderField( "Content-Type",
487 QString( "text/calendar; method=%1; "
488 "charset=\"utf-8\"" ).
489 arg( attachParamValue ) );
491 iCalAutoSend = true; // no point in editing raw ICAL
492 noWordWrap = true; // we shant word wrap inline invitations
493 } else {
494 // Just do what we're told to do
495 msgPart = new KMMessagePart;
496 msgPart->setName( attachName );
497 msgPart->setCteStr( attachCte );
498 msgPart->setBodyEncoded( attachData );
499 msgPart->setTypeStr( attachType );
500 msgPart->setSubtypeStr( attachSubType );
501 msgPart->setParameter( attachParamAttr, attachParamValue );
502 if( ! GlobalSettings::self()->exchangeCompatibleInvitations() ) {
503 msgPart->setContentDisposition( attachContDisp );
505 if( !attachCharset.isEmpty() ) {
506 // kDebug(5006) <<"KMKernel::openComposer set attachCharset to"
507 // << attachCharset;
508 msgPart->setCharset( attachCharset );
510 // Don't show the composer window, if the automatic sending is checked
511 KConfigGroup options( config(), "Groupware" );
512 iCalAutoSend = options.readEntry( "AutomaticSending", true );
516 KMail::Composer * cWin = KMail::makeComposer();
517 cWin->setMsg( msg, !isICalInvitation /* mayAutoSign */ );
518 cWin->setSigningAndEncryptionDisabled( isICalInvitation
519 && GlobalSettings::self()->legacyBodyInvites() );
520 cWin->setAutoDelete( true );
521 if( noWordWrap )
522 cWin->slotWordWrapToggled( false );
523 else
524 cWin->setCharset( "", true );
525 if ( msgPart )
526 cWin->addAttach(msgPart);
528 if ( hidden == 0 && !iCalAutoSend ) {
529 cWin->show();
530 // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
531 // so that it also works when called from KMailApplication::newInstance()
532 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
533 KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
534 #endif
535 } else {
536 cWin->slotSendNow();
539 return 1;
542 void KMKernel::setDefaultTransport( const QString & transport )
544 MailTransport::Transport *t = MailTransport::TransportManager::self()->transportByName( transport, false );
545 if ( !t ) {
546 kWarning(5006) <<"The transport you entered is not available";
547 return;
549 MailTransport::TransportManager::self()->setDefaultTransport( t->id() );
552 QDBusObjectPath KMKernel::openComposer(const QString &to, const QString &cc,
553 const QString &bcc, const QString &subject,
554 const QString &body,bool hidden)
556 KMMessage *msg = new KMMessage;
557 msg->initHeader();
558 msg->setCharset("utf-8");
559 if (!cc.isEmpty()) msg->setCc(cc);
560 if (!bcc.isEmpty()) msg->setBcc(bcc);
561 if (!subject.isEmpty()) msg->setSubject(subject);
562 if (!to.isEmpty()) msg->setTo(to);
563 if ( !body.isEmpty() ) {
564 msg->setBody(body.toUtf8());
565 } else {
566 TemplateParser parser( msg, TemplateParser::NewMessage,
567 QString(), false, false, false );
568 parser.process( NULL, NULL );
571 KMail::Composer * cWin = KMail::makeComposer( msg );
572 cWin->setCharset("", true);
573 if (!hidden) {
574 cWin->show();
575 // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
576 // so that it also works when called from KMailApplication::newInstance()
577 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
578 KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
579 #endif
582 return QDBusObjectPath(cWin->dbusObjectPath());
585 QDBusObjectPath KMKernel::newMessage(const QString &to,
586 const QString &cc,
587 const QString &bcc,
588 bool hidden,
589 bool useFolderId,
590 const QString & /*messageFile*/,
591 const QString &_attachURL)
593 KUrl attachURL(_attachURL);
594 KMail::Composer * win = 0;
595 KMMessage *msg = new KMMessage;
596 KMFolder *folder = NULL;
597 uint id = 0;
599 if ( useFolderId ) {
600 //create message with required folder identity
601 folder = currentFolder();
602 id = folder ? folder->identity() : 0;
603 msg->initHeader( id );
604 win = makeComposer( msg, id );
605 } else {
606 msg->initHeader();
607 win = makeComposer( msg );
609 msg->setCharset("utf-8");
610 //set basic headers
611 if (!to.isEmpty()) msg->setTo(to);
612 if (!cc.isEmpty()) msg->setCc(cc);
613 if (!bcc.isEmpty()) msg->setBcc(bcc);
615 if ( useFolderId ) {
616 TemplateParser parser( msg, TemplateParser::NewMessage,
617 QString(), false, false, false );
618 parser.process( NULL, folder );
619 win = makeComposer( msg, id );
620 } else {
621 TemplateParser parser( msg, TemplateParser::NewMessage,
622 QString(), false, false, false );
623 parser.process( NULL, NULL );
624 win = makeComposer( msg );
627 //Add the attachment if we have one
628 if(!attachURL.isEmpty() && attachURL.isValid()) {
629 win->addAttach(attachURL);
632 //only show window when required
633 if(!hidden) {
634 win->show();
636 return QDBusObjectPath(win->dbusObjectPath());
639 int KMKernel::viewMessage( const KUrl & messageFile )
641 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( 0, messageFile );
643 openCommand->start();
645 return 1;
648 int KMKernel::sendCertificate( const QString& to, const QByteArray& certData )
650 KMMessage *msg = new KMMessage;
651 msg->initHeader();
652 msg->setCharset("utf-8");
653 msg->setSubject( i18n( "Certificate Signature Request" ) );
654 if (!to.isEmpty()) msg->setTo(to);
655 // ### Make this message customizable via KIOSK
656 msg->setBody( i18n( "Please create a certificate from attachment and return to sender." ).toUtf8() );
658 KMail::Composer * cWin = KMail::makeComposer( msg );
659 cWin->setCharset("", true);
660 cWin->slotSetAlwaysSend( true );
661 if (!certData.isEmpty()) {
662 KMMessagePart *msgPart = new KMMessagePart;
663 msgPart->setName("smime.p10");
664 msgPart->setCteStr("base64");
665 msgPart->setBodyEncodedBinary(certData);
666 msgPart->setTypeStr("application");
667 msgPart->setSubtypeStr("pkcs10");
668 msgPart->setContentDisposition("attachment; filename=smime.p10");
669 cWin->addAttach(msgPart);
672 cWin->show();
673 return 1;
676 int KMKernel::dbusAddMessage( const QString & foldername, const QString & msgUrlString,
677 const QString & MsgStatusFlags)
679 return dbusAddMessage(foldername, KUrl(msgUrlString), MsgStatusFlags);
682 int KMKernel::dbusAddMessage( const QString & foldername,const KUrl & msgUrl,
683 const QString & MsgStatusFlags)
685 kDebug(5006) <<"KMKernel::dbusAddMessage called";
687 if ( foldername.isEmpty() || foldername.startsWith('.'))
688 return -1;
690 int retval;
691 bool readFolderMsgIds = false;
692 QString _foldername = foldername.trimmed();
693 _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences
695 if ( foldername != mAddMessageLastFolder ) {
696 mAddMessageMsgIds.clear();
697 readFolderMsgIds = true;
698 mAddMessageLastFolder = foldername;
701 if (!msgUrl.isEmpty() && msgUrl.isLocalFile()) {
703 const QByteArray messageText =
704 KPIMUtils::kFileToByteArray( msgUrl.path(), true, false );
705 if ( messageText.isEmpty() )
706 return -2;
708 KMMessage *msg = new KMMessage();
709 msg->fromString( messageText );
711 if (readFolderMsgIds) {
712 if ( foldername.contains("/")) {
713 QString tmp_fname = "";
714 KMFolder *folder = NULL;
715 KMFolderDir *subfolder;
716 bool root = true;
718 QStringList subFList = _foldername.split("/", QString::SkipEmptyParts);
720 for ( QStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
721 QString _newFolder = *it;
722 if(_newFolder.startsWith('.')) return -1;
724 if(root) {
725 folder = the_folderMgr->findOrCreate(*it, false);
726 if (folder) {
727 root = false;
728 tmp_fname = '/' + *it;
730 else return -1;
732 else {
733 subfolder = folder->createChildFolder();
734 tmp_fname += '/' + *it;
735 if(!the_folderMgr->getFolderByURL( tmp_fname )) {
736 folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder);
739 if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
743 mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
744 if(!folder) return -1;
747 else {
748 mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
752 if ( mAddMsgCurrentFolder ) {
753 if (readFolderMsgIds) {
755 // OLD COMMENT:
756 // Try to determine if a message already exists in
757 // the folder. The message id that is searched for, is
758 // the subject line + the date. This should be quite
759 // unique. The change that a given date with a given
760 // subject is in the folder twice is very small.
761 // If the subject is empty, the fromStrip string
762 // is taken.
764 // NEW COMMENT from Danny Kukawka (danny.kukawka@web.de):
765 // subject line + the date is only unique if the following
766 // return a correct unique value:
767 // time_t DT = mb->date();
768 // QString dt = ctime(&DT);
769 // But if the datestring in the Header isn't RFC conform
770 // subject line + the date isn't unique.
772 // The only uique headerfield is the Message-ID. In some
773 // cases this could be empty. I then I use the
774 // subject line + dateStr .
776 int i;
778 mAddMsgCurrentFolder->open( "dbusadd" );
779 for( i=0; i<mAddMsgCurrentFolder->count(); i++) {
780 KMMsgBase *mb = mAddMsgCurrentFolder->getMsgBase(i);
781 QString id = mb->msgIdMD5();
782 if ( id.isEmpty() ) {
783 id = mb->subject();
784 if ( id.isEmpty() )
785 id = mb->fromStrip();
786 if ( id.isEmpty() )
787 id = mb->toStrip();
789 id += mb->dateStr();
792 //fprintf(stderr,"%s\n",(const char *) id);
793 if ( !id.isEmpty() ) {
794 mAddMessageMsgIds.append(id);
797 mAddMsgCurrentFolder->close( "dbusadd" );
800 QString msgId = msg->msgIdMD5();
801 if ( msgId.isEmpty()) {
802 msgId = msg->subject();
803 if ( msgId.isEmpty() )
804 msgId = msg->fromStrip();
805 if ( msgId.isEmpty() )
806 msgId = msg->toStrip();
808 msgId += msg->dateStr();
811 int k = mAddMessageMsgIds.indexOf( msgId );
812 //fprintf(stderr,"find %s = %d\n",(const char *) msgId,k);
814 if ( k == -1 ) {
815 if ( !msgId.isEmpty() ) {
816 mAddMessageMsgIds.append( msgId );
819 if ( !MsgStatusFlags.isEmpty() ) {
820 msg->status().setStatusFromStr(MsgStatusFlags);
823 int index;
824 if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
825 mAddMsgCurrentFolder->unGetMsg( index );
826 retval = 1;
827 } else {
828 retval =- 2;
829 delete msg;
830 msg = 0;
832 } else {
833 //qDebug( "duplicate: " + msgId + "; subj: " + msg->subject() + ", from: " + msgId = msg->fromStrip());
834 retval = -4;
836 } else {
837 retval = -1;
839 } else {
840 retval = -2;
842 return retval;
845 void KMKernel::dbusResetAddMessage()
847 mAddMessageMsgIds.clear();
848 mAddMessageLastFolder.clear();
851 int KMKernel::dbusAddMessage_fastImport( const QString & foldername,
852 const QString & msgUrlString,
853 const QString & MsgStatusFlags)
855 return dbusAddMessage_fastImport(foldername, KUrl(msgUrlString), MsgStatusFlags);
858 int KMKernel::dbusAddMessage_fastImport( const QString & foldername,
859 const KUrl & msgUrl,
860 const QString & MsgStatusFlags)
862 // Use this function to import messages without
863 // search for already existing emails.
864 kDebug(5006) <<"KMKernel::dbusAddMessage_fastImport called";
866 if ( foldername.isEmpty() || foldername.startsWith('.'))
867 return -1;
869 int retval;
870 bool createNewFolder = false;
872 QString _foldername = foldername.trimmed();
873 _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences
875 if ( foldername != mAddMessageLastFolder ) {
876 createNewFolder = true;
877 mAddMessageLastFolder = foldername;
881 if ( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) {
882 const QByteArray messageText =
883 KPIMUtils::kFileToByteArray( msgUrl.path(), true, false );
884 if ( messageText.isEmpty() )
885 return -2;
887 KMMessage *msg = new KMMessage();
888 msg->fromString( messageText );
890 if (createNewFolder) {
891 if ( foldername.contains("/")) {
892 QString tmp_fname = "";
893 KMFolder *folder = NULL;
894 KMFolderDir *subfolder;
895 bool root = true;
897 QStringList subFList = _foldername.split("/", QString::SkipEmptyParts);
899 for ( QStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
900 QString _newFolder = *it;
901 if(_newFolder.startsWith('.')) return -1;
903 if(root) {
904 folder = the_folderMgr->findOrCreate(*it, false);
905 if (folder) {
906 root = false;
907 tmp_fname = '/' + *it;
909 else return -1;
911 else {
912 subfolder = folder->createChildFolder();
913 tmp_fname += '/' + *it;
914 if(!the_folderMgr->getFolderByURL( tmp_fname )) {
915 folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder);
917 if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
921 mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
922 if(!folder) return -1;
925 else {
926 mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
930 if ( mAddMsgCurrentFolder ) {
931 int index;
933 if( !MsgStatusFlags.isEmpty() ) {
934 msg->status().setStatusFromStr(MsgStatusFlags);
937 if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
938 mAddMsgCurrentFolder->unGetMsg( index );
939 retval = 1;
940 } else {
941 retval =- 2;
942 delete msg;
943 msg = 0;
945 } else {
946 retval = -1;
948 } else {
949 retval = -2;
952 return retval;
955 QStringList KMKernel::folderList() const
957 QStringList folders;
958 const QString localPrefix = "/Local";
959 folders << localPrefix;
960 the_folderMgr->getFolderURLS( folders, localPrefix );
961 the_imapFolderMgr->getFolderURLS( folders );
962 the_dimapFolderMgr->getFolderURLS( folders );
963 return folders;
966 QString KMKernel::getFolder( const QString& vpath )
968 QString adaptorName;
969 const QString localPrefix = "/Local";
970 if ( the_folderMgr->getFolderByURL( vpath ) )
971 adaptorName=vpath;
972 else if ( vpath.startsWith( localPrefix ) && the_folderMgr->getFolderByURL( vpath.mid( localPrefix.length() ) ) )
973 adaptorName=vpath.mid( localPrefix.length() );
974 else if ( the_imapFolderMgr->getFolderByURL( vpath ) )
975 adaptorName=vpath;
976 else if (the_dimapFolderMgr->getFolderByURL( vpath ) )
977 adaptorName=vpath;
978 if( !adaptorName.isEmpty())
980 if ( folderAdaptor )
982 folderAdaptor->unregisterobject();
983 delete folderAdaptor;
985 folderAdaptor = new KMail::FolderAdaptor(adaptorName);
986 return vpath;
988 kWarning(5006) << "Folder not found:" << vpath;
989 return QString();
992 void KMKernel::raise()
994 QDBusInterface iface(DBUS_KMAIL, "/MainApplication", "org.kde.KUniqueApplication", QDBusConnection::sessionBus());
995 QDBusReply<int> reply;
996 if (!iface.isValid() || !(reply = iface.call("newInstance")).isValid())
998 QDBusError err = iface.lastError();
999 kError() <<"Communication problem with kmail"
1000 << "Error message was:" << err.name() << ": \"" << err.message() << "\"";
1005 bool KMKernel::showMail( quint32 serialNumber, const QString& /* messageId */ )
1007 KMMainWidget *mainWidget = 0;
1008 QObjectList l;
1010 // First look for a KMainWindow.
1011 for ( QList<KMainWindow*>::const_iterator it = KMainWindow::memberList().begin();
1012 it != KMainWindow::memberList().end(); ++it ) {
1013 // Then look for a KMMainWidget.
1014 l = (*it)->queryList("KMMainWidget");
1015 if (!l.isEmpty() && l.first()) {
1016 mainWidget = dynamic_cast<KMMainWidget *>(l.first());
1017 if ( (*it)->isActiveWindow() )
1018 break;
1022 if (mainWidget) {
1023 int idx = -1;
1024 KMFolder *folder = 0;
1025 KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
1026 if (!folder || (idx == -1))
1027 return false;
1028 KMFolderOpener openFolder(folder, "showmail");
1029 KMMsgBase *msgBase = folder->getMsgBase(idx);
1030 if (!msgBase)
1031 return false;
1032 bool unGet = !msgBase->isMessage();
1033 KMMessage *msg = folder->getMsg(idx);
1035 KMReaderMainWin *win = new KMReaderMainWin( false, false );
1036 KMMessage *newMessage = new KMMessage( *msg );
1037 newMessage->setParent( msg->parent() );
1038 newMessage->setMsgSerNum( msg->getMsgSerNum() );
1039 newMessage->setReadyToShow( true );
1040 win->showMsg( GlobalSettings::self()->overrideCharacterEncoding(), newMessage );
1041 win->show();
1043 if (unGet)
1044 folder->unGetMsg(idx);
1045 return true;
1048 return false;
1051 QString KMKernel::getFrom( quint32 serialNumber )
1053 int idx = -1;
1054 KMFolder *folder = 0;
1055 KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
1056 if (!folder || (idx == -1))
1057 return QString();
1058 KMFolderOpener openFolder(folder, "getFrom");
1059 KMMsgBase *msgBase = folder->getMsgBase(idx);
1060 if (!msgBase)
1061 return QString();
1062 bool unGet = !msgBase->isMessage();
1063 KMMessage *msg = folder->getMsg(idx);
1064 QString result = msg->from();
1065 if (unGet)
1066 folder->unGetMsg(idx);
1067 return result;
1070 QString KMKernel::debugScheduler()
1072 QString res = KMail::ActionScheduler::debug();
1073 return res;
1076 QString KMKernel::debugSernum( quint32 serialNumber )
1078 QString res;
1079 if (serialNumber != 0) {
1080 int idx = -1;
1081 KMFolder *folder = 0;
1082 KMMsgBase *msg = 0;
1083 KMMsgDict::instance()->getLocation( serialNumber, &folder, &idx );
1084 // It's possible that the message has been deleted or moved into a
1085 // different folder
1086 if (folder && (idx != -1)) {
1087 // everything is ok
1088 KMFolderOpener openFolder( folder, "debugser" );
1089 msg = folder->getMsgBase( idx );
1090 if (msg) {
1091 res.append( QString( " subject %s,\n sender %s,\n date %s.\n" )
1092 .arg( msg->subject() )
1093 .arg( msg->fromStrip() )
1094 .arg( msg->dateStr() ) );
1095 } else {
1096 res.append( QString( "Invalid serial number." ) );
1098 } else {
1099 res.append( QString( "Invalid serial number." ) );
1102 return res;
1106 void KMKernel::pauseBackgroundJobs()
1108 mBackgroundTasksTimer->stop();
1109 mJobScheduler->pause();
1112 void KMKernel::resumeBackgroundJobs()
1114 mJobScheduler->resume();
1115 mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000 );
1118 void KMKernel::stopNetworkJobs()
1120 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
1121 return;
1123 GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Offline );
1124 BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended"));
1125 emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
1129 void KMKernel::resumeNetworkJobs()
1131 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online )
1132 return;
1134 GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Online );
1135 BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed"));
1136 emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
1138 if ( kmkernel->msgSender()->sendImmediate() ) {
1139 kmkernel->msgSender()->sendQueued();
1143 bool KMKernel::isOffline()
1145 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
1146 return true;
1147 else
1148 return false;
1151 bool KMKernel::askToGoOnline()
1153 if ( kmkernel->isOffline() ) {
1154 int rc =
1155 KMessageBox::questionYesNo( KMKernel::self()->mainWin(),
1156 i18n("KMail is currently in offline mode. "
1157 "How do you want to proceed?"),
1158 i18n("Online/Offline"),
1159 KGuiItem(i18n("Work Online")),
1160 KGuiItem(i18n("Work Offline")));
1162 if( rc == KMessageBox::No ) {
1163 return false;
1164 } else {
1165 kmkernel->resumeNetworkJobs();
1168 return true;
1171 /********************************************************************/
1172 /* Kernel methods */
1173 /********************************************************************/
1175 void KMKernel::quit()
1177 // Called when all windows are closed. Will take care of compacting,
1178 // sending... should handle session management too!!
1180 /* TODO later:
1181 Asuming that:
1182 - msgsender is nonblocking
1183 (our own, QSocketNotifier based. Pops up errors and sends signal
1184 senderFinished when done)
1186 o If we are getting mail, stop it (but don't lose something!)
1187 [Done already, see mailCheckAborted]
1188 o If we are sending mail, go on UNLESS this was called by SM,
1189 in which case stop ASAP that too (can we warn? should we continue
1190 on next start?)
1191 o If we are compacting, or expunging, go on UNLESS this was SM call.
1192 In that case stop compacting ASAP and continue on next start, before
1193 touching any folders. [Not needed anymore with CompactionJob]
1195 KMKernel::quit ()
1197 SM call?
1198 if compacting, stop;
1199 if sending, stop;
1200 if receiving, stop;
1201 Windows will take care of themselves (composer should dump
1202 its messages, if any but not in deadMail)
1203 declare us ready for the End of the Session
1205 No, normal quit call
1206 All windows are off. Anything to do, should compact or sender sends?
1207 Yes, maybe put an icon in panel as a sign of life
1208 if sender sending, connect us to his finished slot, declare us ready
1209 for quit and wait for senderFinished
1210 if not, Folder manager, go compact sent-mail and outbox
1211 } (= call slotFinished())
1213 void KMKernel::slotSenderFinished()
1215 good, Folder manager go compact sent-mail and outbox
1216 clean up stage1 (release folders and config, unregister from dcop)
1217 -- another kmail may start now ---
1218 qApp->quit();
1223 /********************************************************************/
1224 /* Init, Exit, and handler methods */
1225 /********************************************************************/
1226 void KMKernel::testDir(const char *_name)
1228 QString foldersPath = QDir::homePath() + QString( _name );
1229 QFileInfo info( foldersPath );
1230 if ( !info.exists() ) {
1231 #ifdef Q_OS_WIN
1232 if ( ::mkdir( QFile::encodeName( foldersPath ) ) == -1 ) {
1233 #else
1234 if ( ::mkdir( QFile::encodeName( foldersPath ) , S_IRWXU ) == -1 ) {
1235 #endif
1236 KMessageBox::sorry(0, i18n("KMail could not create folder '%1';\n"
1237 "please make sure that you can view and "
1238 "modify the content of the folder '%2'.",
1239 foldersPath, QDir::homePath() ) );
1240 ::exit(-1);
1243 if ( !info.isDir() || !info.isReadable() || !info.isWritable() ) {
1244 KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
1245 "incorrect;\n"
1246 "please make sure that you can view and modify "
1247 "the content of this folder.",
1248 foldersPath ) );
1249 ::exit(-1);
1254 //-----------------------------------------------------------------------------
1255 // Open a composer for each message found in the dead.letter folder
1256 void KMKernel::recoverDeadLetters()
1258 const QString pathName = localDataPath();
1259 QDir dir( pathName );
1260 if ( !dir.exists( "autosave" ) )
1261 return;
1263 KMFolder folder( 0, pathName + "autosave", KMFolderTypeMaildir, false /* no index */ );
1264 KMFolderOpener openFolder( &folder, "recover" );
1265 if ( !folder.isOpened() ) {
1266 perror( "cannot open autosave folder" );
1267 return;
1270 const int num = folder.count();
1271 for ( int i = 0; i < num; i++ ) {
1272 KMMessage *msg = folder.take( 0 );
1273 if ( msg ) {
1274 KMail::Composer * win = KMail::makeComposer();
1275 win->setMsg( msg, false, false, true );
1276 win->setAutoSaveFilename( msg->fileName() );
1277 win->show();
1282 //-----------------------------------------------------------------------------
1283 void KMKernel::initFolders(KConfig* cfg)
1285 QString name;
1286 KConfigGroup group(cfg,"General");
1288 name = group.readEntry("inboxFolder");
1290 // Currently the folder manager cannot manage folders which are not
1291 // in the base folder directory.
1292 //if (name.isEmpty()) name = getenv("MAIL");
1294 if (name.isEmpty()) name = I18N_NOOP("inbox");
1296 the_inboxFolder = (KMFolder*)the_folderMgr->findOrCreate(name);
1298 if (the_inboxFolder->canAccess() != 0) {
1299 emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
1302 the_inboxFolder->setSystemFolder(true);
1303 if ( the_inboxFolder->userWhoField().isEmpty() )
1304 the_inboxFolder->setUserWhoField( QString() );
1305 // inboxFolder->open();
1307 the_outboxFolder = the_folderMgr->findOrCreate(group.readEntry("outboxFolder", I18N_NOOP("outbox")));
1308 if (the_outboxFolder->canAccess() != 0) {
1309 emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
1311 the_outboxFolder->setNoChildren(true);
1313 the_outboxFolder->setSystemFolder(true);
1314 if ( the_outboxFolder->userWhoField().isEmpty() )
1315 the_outboxFolder->setUserWhoField( QString() );
1316 /* Nuke the oubox's index file, to make sure that no ghost messages are in
1317 * it from a previous crash. Ghost messages happen in the outbox because it
1318 * the only folder where messages enter and leave within 5 seconds, which is
1319 * the leniency period for index invalidation. Since the number of mails in
1320 * this folder is expected to be very small, we can live with regenerating
1321 * the index on each start to be on the save side. */
1322 //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir )
1323 // unlink( QFile::encodeName( the_outboxFolder->indexLocation() ) );
1324 the_outboxFolder->open( "kmkernel" );
1326 the_sentFolder = the_folderMgr->findOrCreate(group.readEntry("sentFolder", I18N_NOOP("sent-mail")));
1327 if (the_sentFolder->canAccess() != 0) {
1328 emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
1330 the_sentFolder->setSystemFolder(true);
1331 if ( the_sentFolder->userWhoField().isEmpty() )
1332 the_sentFolder->setUserWhoField( QString() );
1333 // the_sentFolder->open();
1335 the_trashFolder = the_folderMgr->findOrCreate(group.readEntry("trashFolder", I18N_NOOP("trash")));
1336 if (the_trashFolder->canAccess() != 0) {
1337 emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
1339 the_trashFolder->setSystemFolder(true);
1340 if ( the_trashFolder->userWhoField().isEmpty() )
1341 the_trashFolder->setUserWhoField( QString() );
1342 // the_trashFolder->open();
1344 the_draftsFolder = the_folderMgr->findOrCreate(group.readEntry("draftsFolder", I18N_NOOP("drafts")));
1345 if (the_draftsFolder->canAccess() != 0) {
1346 emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
1348 the_draftsFolder->setSystemFolder(true);
1349 if ( the_draftsFolder->userWhoField().isEmpty() )
1350 the_draftsFolder->setUserWhoField( QString() );
1351 the_draftsFolder->open( "kmkernel" );
1353 the_templatesFolder = the_folderMgr->findOrCreate(group.readEntry("templatesFolder", I18N_NOOP("templates")));
1354 if (the_templatesFolder->canAccess() != 0) {
1355 emergencyExit( i18n("You do not have read/write permission to your templates folder.") );
1357 the_templatesFolder->setSystemFolder(true);
1358 if ( the_templatesFolder->userWhoField().isEmpty() )
1359 the_templatesFolder->setUserWhoField( QString() );
1360 the_templatesFolder->open( "kmkernel" );
1364 void KMKernel::init()
1366 the_shuttingDown = false;
1367 the_server_is_ready = false;
1369 KConfig* cfg = KMKernel::config();
1371 QDir dir;
1373 KConfigGroup group(cfg, "General");
1374 the_firstStart = group.readEntry("first-start", true );
1375 group.writeEntry("first-start", false);
1376 the_previousVersion = group.readEntry("previous-version");
1377 group.writeEntry("previous-version", KMAIL_VERSION);
1378 QString foldersPath = group.readPathEntry( "folders" );
1379 kDebug(5006) <<"foldersPath (from config): '" << foldersPath <<"'";
1381 if ( foldersPath.isEmpty() ) {
1382 foldersPath = localDataPath() + "mail";
1383 if ( transferMail( foldersPath ) ) {
1384 group.writePathEntry( "folders", foldersPath );
1386 kDebug(5006) <<"foldersPath (after transferMail): '" << foldersPath <<"'";
1388 //Here because folderMgr's need it when they read the index and sort tags
1389 the_msgTagMgr = new KMMessageTagMgr();
1390 the_msgTagMgr->readConfig();
1392 // moved up here because KMMessage::stripOffPrefixes is used below
1393 KMMessage::readConfig();
1395 the_undoStack = new UndoStack(20);
1396 the_folderMgr = new KMFolderMgr(foldersPath);
1397 the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
1398 the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
1400 the_searchFolderMgr = new KMFolderMgr(KStandardDirs::locateLocal("data","kmail/search"), KMSearchDir);
1401 KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
1402 if (lsf)
1403 the_searchFolderMgr->remove( lsf );
1405 the_acctMgr = new AccountManager();
1406 the_filterMgr = new KMFilterMgr();
1407 the_popFilterMgr = new KMFilterMgr(true);
1408 the_filterActionDict = new KMFilterActionDict;
1410 initFolders(cfg);
1411 the_acctMgr->readConfig();
1412 the_filterMgr->readConfig();
1413 the_popFilterMgr->readConfig();
1414 cleanupImapFolders();
1416 the_msgSender = new KMSender;
1417 the_server_is_ready = true;
1418 { // area for config group "Composer"
1419 KConfigGroup group(cfg, "Composer");
1420 if (group.readEntry("pref-charsets", QStringList() ).isEmpty())
1422 group.writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
1425 readConfig();
1426 // filterMgr->dump();
1428 the_weaver = new ThreadWeaver::Weaver( this );
1430 connect( the_folderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1431 this, SIGNAL( folderRemoved(KMFolder*) ) );
1432 connect( the_dimapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1433 this, SIGNAL( folderRemoved(KMFolder*) ) );
1434 connect( the_imapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1435 this, SIGNAL( folderRemoved(KMFolder*) ) );
1436 connect( the_searchFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1437 this, SIGNAL( folderRemoved(KMFolder*) ) );
1439 mBackgroundTasksTimer = new QTimer( this );
1440 mBackgroundTasksTimer->setSingleShot( true );
1441 connect( mBackgroundTasksTimer, SIGNAL( timeout() ), this, SLOT( slotRunBackgroundTasks() ) );
1442 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
1443 mBackgroundTasksTimer->start( 10000 ); // 10s minute, singleshot
1444 #else
1445 mBackgroundTasksTimer->start( 5 * 60000 ); // 5 minutes, singleshot
1446 #endif
1449 void KMKernel::readConfig()
1451 //Needed here, since this function is also called when the configuration
1452 //changes, and the static variables should be updated then - IOF
1453 KMMessage::readConfig();
1456 void KMKernel::cleanupImapFolders()
1458 KMAccount *acct = 0;
1459 QList<KMFolderNode*>::iterator it = the_imapFolderMgr->dir().begin();
1460 while ( it != the_imapFolderMgr->dir().end() )
1462 KMFolderNode *node = *it;
1463 if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
1464 && ( acct->type() == KAccount::Imap )) )
1466 ++it;
1467 } else {
1468 KMFolder* folder = static_cast<KMFolder*>(node);
1469 // delete only local
1470 static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true );
1471 the_imapFolderMgr->remove(folder);
1472 it = the_imapFolderMgr->dir().begin();
1476 it = the_dimapFolderMgr->dir().begin();
1477 while ( it != the_dimapFolderMgr->dir().end() )
1479 KMFolderNode *node = *it;
1480 if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
1481 && ( acct->type() == KAccount::DImap )) )
1483 ++it;
1484 } else {
1485 the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
1486 it = the_dimapFolderMgr->dir().begin();
1490 the_imapFolderMgr->quiet(true);
1491 for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
1493 KMFolderImap *fld;
1494 KMAcctImap *imapAcct;
1496 if (acct->type() != KAccount::Imap) continue;
1497 fld = static_cast<KMFolderImap*>(the_imapFolderMgr
1498 ->findOrCreate(QString::number(acct->id()), false, acct->id())->storage());
1499 fld->setNoContent(true);
1500 fld->folder()->setLabel(acct->name());
1501 imapAcct = static_cast<KMAcctImap*>(acct);
1502 fld->setAccount(imapAcct);
1503 imapAcct->setImapFolder(fld);
1504 fld->close( "kernel", true );
1506 the_imapFolderMgr->quiet(false);
1508 the_dimapFolderMgr->quiet( true );
1509 for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
1511 KMFolderCachedImap *cfld = 0;
1512 KMAcctCachedImap *cachedImapAcct;
1514 if (acct->type() != KAccount::DImap ) continue;
1516 KMFolder* fld = the_dimapFolderMgr->find(QString::number(acct->id()));
1517 if( fld )
1518 cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
1519 if (cfld == 0) {
1520 // Folder doesn't exist yet
1521 cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(QString::number(acct->id()),
1522 false, KMFolderTypeCachedImap)->storage());
1523 if (!cfld) {
1524 KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.", acct->name(), the_dimapFolderMgr->basePath())));
1525 exit(-1);
1527 cfld->folder()->setId( acct->id() );
1530 cfld->setNoContent(true);
1531 cfld->folder()->setLabel(acct->name());
1532 cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
1533 cfld->setAccount(cachedImapAcct);
1534 cachedImapAcct->setImapFolder(cfld);
1535 cfld->close( "kmkernel" );
1537 the_dimapFolderMgr->quiet( false );
1540 bool KMKernel::doSessionManagement()
1543 // Do session management
1544 if (kapp->isSessionRestored()){
1545 int n = 1;
1546 while (KMMainWin::canBeRestored(n)){
1547 //only restore main windows! (Matthias);
1548 if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
1549 (new KMMainWin)->restore(n);
1550 n++;
1552 return true; // we were restored by SM
1554 return false; // no, we were not restored
1557 void KMKernel::closeAllKMailWindows()
1559 QListIterator<KMainWindow*> it( KMainWindow::memberList() );
1560 KMainWindow *window = 0;
1561 while ( it.hasNext() ) {
1562 window = it.next();
1563 if ( ::qobject_cast<KMMainWin *>(window) ||
1564 ::qobject_cast<KMail::SecondaryWindow *>(window) )
1566 window->setAttribute(Qt::WA_DeleteOnClose);
1567 window->close(); // close and delete the window
1572 void KMKernel::cleanup(void)
1574 dumpDeadLetters();
1575 the_shuttingDown = true;
1576 closeAllKMailWindows();
1578 delete the_acctMgr;
1579 the_acctMgr = 0;
1580 delete the_filterMgr;
1581 the_filterMgr = 0;
1582 delete the_msgSender;
1583 the_msgSender = 0;
1584 delete the_filterActionDict;
1585 the_filterActionDict = 0;
1586 delete the_msgTagMgr;
1587 the_msgTagMgr = 0;
1588 delete the_undoStack;
1589 the_undoStack = 0;
1590 delete the_popFilterMgr;
1591 the_popFilterMgr = 0;
1593 delete the_weaver;
1594 the_weaver = 0;
1596 KConfig* config = KMKernel::config();
1597 KConfigGroup group(config, "General");
1599 if ( the_trashFolder ) {
1601 the_trashFolder->close( "kmkernel", true );
1603 if ( group.readEntry( "empty-trash-on-exit", true ) ) {
1604 if ( the_trashFolder->count( true ) > 0 ) {
1605 the_trashFolder->expunge();
1610 if ( mICalIface )
1611 mICalIface->cleanup();
1613 QList<QPointer<KMFolder> > folders;
1614 QStringList strList;
1615 KMFolder *folder;
1616 the_folderMgr->createFolderList(&strList, &folders);
1618 QList<QPointer<KMFolder> >::const_iterator it;
1619 for ( it = folders.begin(); it != folders.end(); it++ ) {
1620 folder = *it;
1621 if ( !folder || folder->isDir() ) {
1622 continue;
1624 folder->close( "kmkernel", true );
1626 strList.clear();
1627 folders.clear();
1628 the_searchFolderMgr->createFolderList(&strList, &folders);
1629 for ( it = folders.begin(); it != folders.end(); it++ ) {
1630 folder = *it;
1631 if ( !folder || folder->isDir() ) {
1632 continue;
1634 folder->close( "kmkernel", true );
1637 delete the_folderMgr;
1638 the_folderMgr = 0;
1639 delete the_imapFolderMgr;
1640 the_imapFolderMgr = 0;
1641 delete the_dimapFolderMgr;
1642 the_dimapFolderMgr = 0;
1643 delete the_searchFolderMgr;
1644 the_searchFolderMgr = 0;
1645 delete mConfigureDialog;
1646 mConfigureDialog = 0;
1647 // do not delete, because mWin may point to an existing window
1648 // delete mWin;
1649 mWin = 0;
1651 if ( RecentAddresses::exists() )
1652 RecentAddresses::self( config )->save( config );
1653 config->sync();
1656 bool KMKernel::transferMail( QString & destinationDir )
1658 QString dir;
1660 // check whether the user has a ~/KMail folder
1661 QFileInfo fi( QDir::home(), "KMail" );
1662 if ( fi.exists() && fi.isDir() ) {
1663 dir = QDir::homePath() + "/KMail";
1664 // the following two lines can be removed once moving mail is reactivated
1665 destinationDir = dir;
1666 return true;
1669 if ( dir.isEmpty() ) {
1670 // check whether the user has a ~/Mail folder
1671 fi.setFile( QDir::home(), "Mail" );
1672 if ( fi.exists() && fi.isDir() &&
1673 QFile::exists( QDir::homePath() + "/Mail/.inbox.index" ) ) {
1674 // there's a ~/Mail folder which seems to be used by KMail (because of the
1675 // index file)
1676 dir = QDir::homePath() + "/Mail";
1677 // the following two lines can be removed once moving mail is reactivated
1678 destinationDir = dir;
1679 return true;
1683 if ( dir.isEmpty() ) {
1684 return true; // there's no old mail folder
1687 #if 0
1688 // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved)
1689 const QString kmailName = KGlobal::mainComponent().aboutData()()->programName();
1690 QString msg;
1691 if ( KIO::NetAccess::exists( destinationDir, KIO::NetAccess::SourceSide, 0 ) ) {
1692 // if destinationDir exists, we need to warn about possible
1693 // overwriting of files. otherwise, we don't have to
1694 msg = ki18nc( "%1-%3 is the application name, %4-%7 are folder path",
1695 "<qt>The <i>%4</i> folder exists. "
1696 "%1 now uses the <i>%5</i> folder for "
1697 "its messages.<p>"
1698 "%2 can move the contents of <i>%6</i> into this folder for "
1699 "you, though this may replace any existing files with "
1700 "the same name in <i>%7</i>.</p><p>"
1701 "<strong>Would you like %3 to move the mail "
1702 "files now?</strong></p></qt>" )
1703 .subs( kmailName ).subs( kmailName ).subs( kmailName )
1704 .subs( dir ).subs( destinationDir ).subs( dir ).subs( destinationDir )
1705 .toString();
1707 else {
1708 msg = ki18nc( "%1-%3 is the application name, %4-%6 are folder path",
1709 "<qt>The <i>%4</i> folder exists. "
1710 "%1 now uses the <i>%5</i> folder for "
1711 "its messages. %2 can move the contents of <i>%6</i> into "
1712 "this folder for you.<p>"
1713 "<strong>Would you like %3 to move the mail "
1714 "files now?</strong></p></qt>" )
1715 .subs( kmailName ).subs( kmailName ).subs( kmailName )
1716 .subs( dir ).subs( destinationDir ).subs( dir )
1717 .toString();
1719 QString title = i18n( "Migrate Mail Files?" );
1720 QString buttonText = i18n( "Move" );
1722 if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) ==
1723 KMessageBox::No ) {
1724 destinationDir = dir;
1725 return true;
1728 if ( !KIO::NetAccess::move( dir, destinationDir ) ) {
1729 kDebug(5006) <<"Moving" << dir <<" to" << destinationDir <<" failed:" << KIO::NetAccess::lastErrorString();
1730 kDebug(5006) <<"Deleting" << destinationDir;
1731 KIO::NetAccess::del( destinationDir, 0 );
1732 destinationDir = dir;
1733 return false;
1735 #endif
1737 return true;
1742 void KMKernel::dumpDeadLetters()
1744 if ( shuttingDown() )
1745 return; //All documents should be saved before shutting down is set!
1747 // make all composer windows autosave their contents
1748 QListIterator<KMainWindow*> it( KMainWindow::memberList() );
1749 while ( it.hasNext() )
1750 if ( KMail::Composer * win = ::qobject_cast<KMail::Composer*>( it.next() ) )
1751 win->autoSaveMessage();
1756 void KMKernel::action( bool mailto, bool check, const QString &to,
1757 const QString &cc, const QString &bcc,
1758 const QString &subj, const QString &body,
1759 const KUrl &messageFile,
1760 const KUrl::List &attachURLs,
1761 const QStringList &customHeaders )
1763 if ( mailto )
1764 openComposer( to, cc, bcc, subj, body, 0, messageFile, attachURLs, customHeaders );
1765 else
1766 openReader( check );
1768 if ( check )
1769 checkMail();
1770 //Anything else?
1773 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KUrl &aURL,
1774 bool overwrite)
1776 // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
1777 KIO::Job *job = KIO::put(aURL, -1, overwrite ? KIO::Overwrite : KIO::DefaultFlags);
1778 putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
1779 mPutJobs.insert(job, pd);
1780 connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
1781 SLOT(slotDataReq(KIO::Job*,QByteArray&)));
1782 connect(job, SIGNAL(result(KJob*)),
1783 SLOT(slotResult(KJob*)));
1786 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
1788 // send the data in 64 KB chunks
1789 const int MAX_CHUNK_SIZE = 64*1024;
1790 QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
1791 assert(it != mPutJobs.end());
1792 int remainingBytes = (*it).data.size() - (*it).offset;
1793 if( remainingBytes > MAX_CHUNK_SIZE )
1795 // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
1796 data = QByteArray( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
1797 (*it).offset += MAX_CHUNK_SIZE;
1798 //kDebug( 5006 ) <<"Sending" << MAX_CHUNK_SIZE <<" bytes ("
1799 // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
1801 else
1803 // send the remaining bytes to the receiver (deep copy)
1804 data = QByteArray( (*it).data.data() + (*it).offset, remainingBytes );
1805 (*it).data = QByteArray();
1806 (*it).offset = 0;
1807 //kDebug( 5006 ) <<"Sending" << remainingBytes <<" bytes";
1811 void KMKernel::slotResult(KJob *job)
1813 QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(static_cast<KIO::Job*>(job));
1814 assert(it != mPutJobs.end());
1815 if (job->error())
1817 if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
1819 if (KMessageBox::warningContinueCancel(0,
1820 i18n("File %1 exists.\nDo you want to replace it?",
1821 (*it).url.prettyUrl()), i18n("Save to File"), KGuiItem(i18n("&Replace")))
1822 == KMessageBox::Continue)
1823 byteArrayToRemoteFile((*it).data, (*it).url, true);
1825 else static_cast<KIO::Job*>(job)->showErrorDialog();
1827 mPutJobs.erase(it);
1830 void KMKernel::slotRequestConfigSync() {
1831 // ### FIXME: delay as promised in the kdoc of this function ;-)
1832 KMKernel::config()->sync();
1835 void KMKernel::slotShowConfigurationDialog()
1837 if( !mConfigureDialog ) {
1838 mConfigureDialog = new ConfigureDialog( 0, false );
1839 mConfigureDialog->setObjectName( "configure" );
1840 connect( mConfigureDialog, SIGNAL( configCommitted() ),
1841 this, SLOT( slotConfigChanged() ) );
1844 if( KMKernel::getKMMainWidget() == 0 ) {
1845 // ensure that there is a main widget available
1846 // as parts of the configure dialog (identity) rely on this
1847 // and this slot can be called when there is only a KMComposeWin showing
1848 KMMainWin *win = new KMMainWin;
1849 win->show();
1853 if( mConfigureDialog->isHidden() ) {
1854 mConfigureDialog->show();
1855 } else {
1856 mConfigureDialog->raise();
1860 void KMKernel::slotConfigChanged()
1862 readConfig();
1863 emit configChanged();
1866 //-------------------------------------------------------------------------------
1867 //static
1868 QString KMKernel::localDataPath()
1870 return KStandardDirs::locateLocal( "data", "kmail/" );
1873 //-------------------------------------------------------------------------------
1875 bool KMKernel::haveSystemTrayApplet()
1877 return !systemTrayApplets.isEmpty();
1880 bool KMKernel::registerSystemTrayApplet( const KSystemTrayIcon* applet )
1882 if ( !systemTrayApplets.contains( applet ) ) {
1883 systemTrayApplets.append( applet );
1884 return true;
1886 else
1887 return false;
1890 bool KMKernel::unregisterSystemTrayApplet( const KSystemTrayIcon* applet )
1892 return systemTrayApplets.removeAll( applet ) > 0;
1895 void KMKernel::emergencyExit( const QString& reason )
1897 QString mesg;
1898 if ( reason.length() == 0 ) {
1899 mesg = i18n("KMail encountered a fatal error and will terminate now");
1901 else {
1902 mesg = i18n("KMail encountered a fatal error and will "
1903 "terminate now.\nThe error was:\n%1", reason );
1906 kWarning(5006) << mesg;
1907 KNotification::event(KNotification::Catastrophe, mesg);
1909 ::exit(1);
1913 * Returns true if the folder is either the outbox or one of the drafts-folders
1915 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
1917 assert( folder );
1918 if ( folder == the_outboxFolder )
1919 return true;
1920 return folderIsDrafts( folder );
1923 bool KMKernel::folderIsDrafts(const KMFolder * folder)
1925 assert( folder );
1926 if ( folder == the_draftsFolder )
1927 return true;
1929 QString idString = folder->idString();
1930 if ( idString.isEmpty() ) return false;
1932 // search the identities if the folder matches the drafts-folder
1933 const KPIMIdentities::IdentityManager * im = identityManager();
1934 for( KPIMIdentities::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
1935 if ( (*it).drafts() == idString ) return true;
1936 return false;
1939 bool KMKernel::folderIsTemplates(const KMFolder * folder)
1941 assert( folder );
1942 if ( folder == the_templatesFolder )
1943 return true;
1945 QString idString = folder->idString();
1946 if ( idString.isEmpty() ) return false;
1948 // search the identities if the folder matches the templates-folder
1949 const KPIMIdentities::IdentityManager * im = identityManager();
1950 for( KPIMIdentities::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
1951 if ( (*it).templates() == idString ) return true;
1952 return false;
1955 bool KMKernel::folderIsTrash(KMFolder * folder)
1957 assert(folder);
1958 if (folder == the_trashFolder) return true;
1959 QStringList actList = acctMgr()->getAccounts();
1960 QStringList::Iterator it( actList.begin() );
1961 for( ; it != actList.end() ; ++it ) {
1962 KMAccount* act = acctMgr()->findByName( *it );
1963 if ( act && ( act->trash() == folder->idString() ) )
1964 return true;
1966 return false;
1969 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
1971 assert( folder );
1972 if ( folder == the_sentFolder )
1973 return true;
1975 QString idString = folder->idString();
1976 if ( idString.isEmpty() ) return false;
1978 // search the identities if the folder matches the sent-folder
1979 const KPIMIdentities::IdentityManager * im = identityManager();
1980 for( KPIMIdentities::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
1981 if ( (*it).fcc() == idString ) return true;
1982 return false;
1985 KPIMIdentities::IdentityManager * KMKernel::identityManager() {
1986 if ( !mIdentityManager ) {
1987 kDebug(5006) <<"instantating KPIMIdentities::IdentityManager";
1988 mIdentityManager = new KPIMIdentities::IdentityManager( false, this, "mIdentityManager" );
1990 return mIdentityManager;
1993 KMainWindow* KMKernel::mainWin()
1995 KMainWindow *kmWin = 0;
1997 // First look for a KMMainWin.
1998 for ( QList<KMainWindow*>::const_iterator it = KMainWindow::memberList().begin();
1999 it != KMainWindow::memberList().end(); ++it )
2000 if ( ::qobject_cast<KMMainWin *>(*it) )
2001 return kmWin;
2003 // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
2004 // case we are running inside Kontact) because we anyway only need
2005 // it for modal message boxes and for KNotify events.
2006 kmWin = KMainWindow::memberList().first();
2007 if ( kmWin )
2008 return kmWin;
2010 // There's not a single KMainWindow. Create a KMMainWin.
2011 // This could happen if we want to pop up an error message
2012 // while we are still doing the startup wizard and no other
2013 // KMainWindow is running.
2014 mWin = new KMMainWin;
2015 return mWin;
2020 * Empties all trash folders
2022 void KMKernel::slotEmptyTrash()
2024 QString title = i18n("Empty Trash");
2025 QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
2026 if (KMessageBox::warningContinueCancel(0, text, title,
2027 KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
2028 "confirm_empty_trash")
2029 != KMessageBox::Continue)
2031 return;
2034 for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
2036 KMFolder* trash = findFolderById(acct->trash());
2037 if (trash)
2039 trash->expunge();
2044 KConfig* KMKernel::config()
2046 assert(mySelf);
2047 if (!mySelf->mConfig)
2049 mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
2050 // Check that all updates have been run on the config file:
2051 KMail::checkConfigUpdates();
2053 return mySelf->mConfig.data();
2056 KMailICalIfaceImpl& KMKernel::iCalIface()
2058 assert( mICalIface );
2059 return *mICalIface;
2062 void KMKernel::selectFolder( const QString &folderPath )
2064 kDebug(5006)<<"Selecting a folder"<<folderPath;
2065 const QString localPrefix = "/Local";
2066 KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
2067 if ( !folder && folderPath.startsWith( localPrefix ) )
2068 folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
2069 if ( !folder )
2070 folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
2071 if ( !folder )
2072 folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
2073 Q_ASSERT( folder );
2075 KMMainWidget *widget = getKMMainWidget();
2076 Q_ASSERT( widget );
2077 if ( !widget )
2078 return;
2080 KMFolderTree *tree = widget->folderTree();
2081 tree->doFolderSelected( tree->indexOfFolder( folder ) );
2082 tree->ensureItemVisible( tree->indexOfFolder( folder ) );
2085 KMMainWidget *KMKernel::getKMMainWidget()
2087 //This could definitely use a speadup
2088 QWidgetList l = QApplication::topLevelWidgets();
2089 QWidget *wid;
2091 Q_FOREACH( wid, l ) {
2092 QObjectList l2 = wid->topLevelWidget()->queryList( "KMMainWidget" );
2093 if (!l2.isEmpty() && l2.first()) {
2094 KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2.first() );
2095 Q_ASSERT( kmmw );
2096 return kmmw;
2099 return 0;
2102 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
2104 // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
2105 // a stable kmail release goes out with a nasty bug in CompactionJob...
2106 KConfigGroup generalGroup( config(), "General" );
2108 if ( generalGroup.readEntry( "auto-expiring", true ) ) {
2109 the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2110 the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2111 the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2112 // the_searchFolderMgr: no expiry there
2115 if ( generalGroup.readEntry( "auto-compaction", true ) ) {
2116 the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
2117 // the_imapFolderMgr: no compaction
2118 the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
2119 // the_searchFolderMgr: no compaction
2122 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
2123 mBackgroundTasksTimer->start( 60 * 1000 ); // check again in 1 minute
2124 #else
2125 mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000 ); // check again in 4 hours
2126 #endif
2130 void KMKernel::expireAllFoldersNow() // called by the GUI
2132 the_folderMgr->expireAllFolders( true /*immediate*/ );
2133 the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
2134 the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
2137 void KMKernel::compactAllFolders() // called by the GUI
2139 the_folderMgr->compactAllFolders( true /*immediate*/ );
2140 //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
2141 the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
2144 KMFolder* KMKernel::findFolderById( const QString& idString )
2146 KMFolder * folder = the_folderMgr->findIdString( idString );
2147 if ( !folder )
2148 folder = the_imapFolderMgr->findIdString( idString );
2149 if ( !folder )
2150 folder = the_dimapFolderMgr->findIdString( idString );
2151 if ( !folder )
2152 folder = the_searchFolderMgr->findIdString( idString );
2153 return folder;
2156 void KMKernel::enableMailCheck()
2158 mMailCheckAborted = false;
2161 bool KMKernel::mailCheckAborted() const
2163 return mMailCheckAborted;
2166 void KMKernel::abortMailCheck()
2168 mMailCheckAborted = true;
2171 bool KMKernel::canQueryClose()
2173 if ( KMMainWidget::mainWidgetList() &&
2174 KMMainWidget::mainWidgetList()->count() > 1 )
2175 return true;
2176 KMMainWidget *widget = getKMMainWidget();
2177 if ( !widget )
2178 return true;
2179 KMSystemTray* systray = widget->systray();
2180 if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
2181 systray->hideKMail();
2182 return false;
2183 } else if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
2184 systray->show();
2185 systray->hideKMail();
2186 return false;
2188 return true;
2191 void KMKernel::messageCountChanged()
2193 mTimeOfLastMessageCountChange = ::time( 0 );
2196 int KMKernel::timeOfLastMessageCountChange() const
2198 return mTimeOfLastMessageCountChange;
2201 Wallet *KMKernel::wallet() {
2202 static bool walletOpenFailed = false;
2203 if ( mWallet && mWallet->isOpen() )
2204 return mWallet;
2206 if ( !Wallet::isEnabled() || walletOpenFailed )
2207 return 0;
2209 // find an appropriate parent window for the wallet dialog
2210 WId window = 0;
2211 if ( qApp->activeWindow() )
2212 window = qApp->activeWindow()->winId();
2213 else if ( getKMMainWidget() )
2214 window = getKMMainWidget()->topLevelWidget()->winId();
2216 delete mWallet;
2217 mWallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
2219 if ( !mWallet ) {
2220 walletOpenFailed = true;
2221 return 0;
2224 if ( !mWallet->hasFolder( "kmail" ) )
2225 mWallet->createFolder( "kmail" );
2226 mWallet->setFolder( "kmail" );
2227 return mWallet;
2230 QList< QPointer<KMFolder> > KMKernel::allFolders()
2232 QStringList names;
2233 QList<QPointer<KMFolder> > folders;
2234 folderMgr()->createFolderList(&names, &folders);
2235 imapFolderMgr()->createFolderList(&names, &folders);
2236 dimapFolderMgr()->createFolderList(&names, &folders);
2237 searchFolderMgr()->createFolderList(&names, &folders);
2239 return folders;
2242 KMFolder *KMKernel::currentFolder() {
2243 KMMainWidget *widget = getKMMainWidget();
2244 KMFolder *folder = 0;
2245 if ( widget && widget->folderTree() ) {
2246 folder = widget->folderTree()->currentFolder();
2248 return folder;
2251 // can't be inline, since KMSender isn't known to implement
2252 // KMail::MessageSender outside this .cpp file
2253 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; }
2255 void KMKernel::transportRemoved(int id, const QString & name)
2257 Q_UNUSED( id );
2259 // reset all identities using the deleted transport
2260 QStringList changedIdents;
2261 KPIMIdentities::IdentityManager * im = identityManager();
2262 for ( KPIMIdentities::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
2263 if ( name == (*it).transport() ) {
2264 (*it).setTransport( QString() );
2265 changedIdents += (*it).identityName();
2269 // if the deleted transport is the currently used transport reset it to default
2270 const QString& currentTransport = GlobalSettings::self()->currentTransport();
2271 if ( name == currentTransport )
2272 GlobalSettings::self()->setCurrentTransport( QString() );
2274 if ( !changedIdents.isEmpty() ) {
2275 QString information = i18np( "This identity has been changed to use the default transport:",
2276 "These %1 identities have been changed to use the default transport:",
2277 changedIdents.count() );
2278 KMessageBox::informationList( mWin, information, changedIdents );
2279 im->commit();
2283 void KMKernel::transportRenamed(int id, const QString & oldName, const QString & newName)
2285 Q_UNUSED( id );
2287 QStringList changedIdents;
2288 KPIMIdentities::IdentityManager * im = identityManager();
2289 for ( KPIMIdentities::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
2290 if ( oldName == (*it).transport() ) {
2291 (*it).setTransport( newName );
2292 changedIdents << (*it).identityName();
2296 if ( !changedIdents.isEmpty() ) {
2297 QString information =
2298 i18np( "This identity has been changed to use the modified transport:",
2299 "These %1 identities have been changed to use the modified transport:",
2300 changedIdents.count() );
2301 KMessageBox::informationList( mWin, information, changedIdents );
2302 im->commit();
2306 #include "kmkernel.moc"