fix errors found while translating
[kdepim.git] / kmail / kmkernel.cpp
blobfb00521fb7414839d6bae1da21c0e92f98e8d665
1 /* -*- mode: C++; c-file-style: "gnu" -*- */
3 #include "kmkernel.h"
5 #include <config-kmail.h>
7 #include "globalsettings.h"
8 #include "broadcaststatus.h"
9 using KPIM::BroadcastStatus;
10 #include "kmstartup.h"
11 #include "kmmainwin.h"
12 #include "composer.h"
13 #include "kmmsgpart.h"
14 #include "kmreadermainwin.h"
15 #include "kmfoldermgr.h"
16 #include "kmfoldercachedimap.h"
17 #include "kmacctcachedimap.h"
18 #include "kmfiltermgr.h"
19 #include "kmfilteraction.h"
20 #define REALLY_WANT_KMSENDER
21 #include "kmsender.h"
22 #undef REALLY_WANT_KMSENDER
23 #include "undostack.h"
24 #include "accountmanager.h"
25 using KMail::AccountManager;
26 #include <kpimutils/kfileio.h>
27 #include "kmversion.h"
28 #include "kmreaderwin.h"
29 #include "kmmainwidget.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 <kde_file.h>
43 #include <kwindowsystem.h>
44 #include "kmailicalifaceimpl.h"
45 #include "mailserviceimpl.h"
46 using KMail::MailServiceImpl;
47 #include "jobscheduler.h"
48 #include "templateparser.h"
49 using KMail::TemplateParser;
50 #include "mainfolderview.h"
52 #include <kmessagebox.h>
53 #include <knotification.h>
54 #include <kstandarddirs.h>
55 #include <kconfig.h>
56 #include <kpassivepopup.h>
57 #include <kapplication.h>
58 #include <ksystemtrayicon.h>
59 #include <kconfiggroup.h>
60 #include <libkpgp/kpgp.h>
61 #include <kdebug.h>
62 #include <kio/jobuidelegate.h>
63 #include <kio/netaccess.h>
64 #include <kwallet.h>
65 using KWallet::Wallet;
66 #include "actionscheduler.h"
68 #include <QByteArray>
69 #include <QDir>
70 #include <QList>
71 #include <QObject>
72 #include <QWidget>
73 #include <QFileInfo>
75 #include <sys/types.h>
76 #include <dirent.h>
77 #include <sys/stat.h>
78 #include <unistd.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <assert.h>
83 #include <kcmdlineargs.h>
84 #include <kstartupinfo.h>
85 #include <kmailadaptor.h>
86 #include "kmailinterface.h"
88 #include "folderadaptor.h"
89 #include "groupware_types.h"
91 static KMKernel * mySelf = 0;
93 /********************************************************************/
94 /* Constructor and destructor */
95 /********************************************************************/
96 KMKernel::KMKernel (QObject *parent, const char *name) :
97 QObject(parent),
98 mIdentityManager(0), mConfigureDialog(0), mICalIface(0), mMailService(0),
99 mContextMenuShown( false ), mWallet( 0 )
101 kDebug(5006);
102 setObjectName( name );
103 mySelf = this;
104 the_startingUp = true;
105 closed_by_user = true;
106 the_firstInstance = true;
108 the_inboxFolder = 0;
109 the_outboxFolder = 0;
110 the_sentFolder = 0;
111 the_trashFolder = 0;
112 the_draftsFolder = 0;
113 the_templatesFolder = 0;
115 the_folderMgr = 0;
116 the_imapFolderMgr = 0;
117 the_dimapFolderMgr = 0;
118 the_searchFolderMgr = 0;
119 the_undoStack = 0;
120 the_acctMgr = 0;
121 the_filterMgr = 0;
122 the_popFilterMgr = 0;
123 the_filterActionDict = 0;
124 the_msgSender = 0;
125 the_msgTagMgr = 0;
126 mWin = 0;
127 mMailCheckAborted = false;
128 folderAdaptor=0;
129 // make sure that we check for config updates before doing anything else
130 KMKernel::config();
131 // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it
132 // so better do it here, than in some code where changing the group of config()
133 // would be unexpected
134 GlobalSettings::self();
136 mJobScheduler = new JobScheduler( this );
137 mICalIface = new KMailICalIfaceImpl();
139 mXmlGuiInstance = KComponentData();
141 new Kpgp::Module();
143 netCodec = QTextCodec::codecForName( KGlobal::locale()->encoding() );
145 // In the case of Japan. Japanese locale name is "eucjp" but
146 // The Japanese mail systems normally used "iso-2022-jp" of locale name.
147 // We want to change locale name from eucjp to iso-2022-jp at KMail only.
149 // (Introduction to i18n, 6.6 Limit of Locale technology):
150 // EUC-JP is the de-facto standard for UNIX systems, ISO 2022-JP
151 // is the standard for Internet, and Shift-JIS is the encoding
152 // for Windows and Macintosh.
153 if ( netCodec->name().toLower() == "eucjp"
154 #if defined Q_WS_WIN || defined Q_WS_MACX
155 || netCodec->name().toLower() == "shift-jis" // OK?
156 #endif
159 netCodec = QTextCodec::codecForName("jis7");
160 // QTextCodec *cdc = QTextCodec::codecForName("jis7");
161 // QTextCodec::setCodecForLocale(cdc);
162 // KGlobal::locale()->setEncoding(cdc->mibEnum());
165 connect( MailTransport::TransportManager::self(),
166 SIGNAL(transportRemoved(int,QString)),
167 SLOT(transportRemoved(int,QString)) );
168 connect( MailTransport::TransportManager::self(),
169 SIGNAL(transportRenamed(int,QString,QString)),
170 SLOT(transportRenamed(int,QString,QString)) );
173 KMKernel::~KMKernel ()
175 QMap<KIO::Job*, putData>::Iterator it = mPutJobs.begin();
176 while ( it != mPutJobs.end() )
178 KIO::Job *job = it.key();
179 mPutJobs.erase( it );
180 job->kill();
181 it = mPutJobs.begin();
184 delete mICalIface;
185 mICalIface = 0;
186 delete mMailService;
187 mMailService = 0;
189 GlobalSettings::self()->writeConfig();
190 delete mWallet;
191 mWallet = 0;
192 mySelf = 0;
193 kDebug(5006);
196 void KMKernel::setupDBus()
198 (void) new KmailAdaptor( this );
199 QDBusConnection::sessionBus().registerObject( "/KMail", this );
200 mICalIface->registerWithDBus();
201 mICalIface->readConfig();
202 mMailService = new MailServiceImpl();
205 bool KMKernel::handleCommandLine( bool noArgsOpensReader )
207 QString to, cc, bcc, subj, body;
208 QStringList customHeaders;
209 KUrl messageFile;
210 KUrl::List attachURLs;
211 bool mailto = false;
212 bool checkMail = false;
213 bool viewOnly = false;
214 bool calledWithSession = false; // for ignoring '-session foo'
216 // process args:
217 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
218 if (args->isSet("subject"))
220 subj = args->getOption("subject");
221 // if kmail is called with 'kmail -session abc' then this doesn't mean
222 // that the user wants to send a message with subject "ession" but
223 // (most likely) that the user clicked on KMail's system tray applet
224 // which results in KMKernel::raise() calling "kmail kmail newInstance"
225 // via D-Bus which apparently executes the application with the original
226 // command line arguments and those include "-session ..." if
227 // kmail/kontact was restored by session management
228 if ( subj == "ession" ) {
229 subj.clear();
230 calledWithSession = true;
232 else
233 mailto = true;
236 if (args->isSet("cc"))
238 mailto = true;
239 cc = args->getOption("cc");
242 if (args->isSet("bcc"))
244 mailto = true;
245 bcc = args->getOption("bcc");
248 if (args->isSet("msg"))
250 mailto = true;
251 messageFile.setPath( args->getOption("msg") );
254 if (args->isSet("body"))
256 mailto = true;
257 body = args->getOption("body");
260 QStringList attachList = args->getOptionList("attach");
261 if (!attachList.isEmpty())
263 mailto = true;
264 for ( QStringList::Iterator it = attachList.begin() ; it != attachList.end() ; ++it )
265 if ( !(*it).isEmpty() )
266 attachURLs += KUrl( *it );
269 customHeaders = args->getOptionList("header");
271 if (args->isSet("composer"))
272 mailto = true;
274 if (args->isSet("check"))
275 checkMail = true;
277 if ( args->isSet( "view" ) ) {
278 viewOnly = true;
279 const QString filename =
280 args->getOption( "view" );
281 messageFile = KUrl( filename );
282 if ( !messageFile.isValid() ) {
283 messageFile = KUrl();
284 messageFile.setPath( filename );
288 if ( !calledWithSession ) {
289 // only read additional command line arguments if kmail/kontact is
290 // not called with "-session foo"
291 for(int i= 0; i < args->count(); i++)
293 if (args->arg(i).startsWith("mailto:", Qt::CaseInsensitive))
294 to += args->url(i).path() + ", ";
295 else {
296 QString tmpArg = args->arg(i);
297 KUrl url( tmpArg );
298 if (url.isValid() && !url.protocol().isEmpty())
299 attachURLs += url;
300 else
301 to += tmpArg + ", ";
303 mailto = true;
305 if ( !to.isEmpty() ) {
306 // cut off the superfluous trailing ", "
307 to.truncate( to.length() - 2 );
311 if ( !calledWithSession )
312 args->clear();
314 if ( !noArgsOpensReader && !mailto && !checkMail && !viewOnly )
315 return false;
317 if ( viewOnly )
318 viewMessage( messageFile );
319 else
320 action( mailto, checkMail, to, cc, bcc, subj, body, messageFile,
321 attachURLs, customHeaders );
322 return true;
325 /********************************************************************/
326 /* DCOP-callable, and command line actions */
327 /********************************************************************/
328 void KMKernel::checkMail () //might create a new reader but won't show!!
330 if ( !kmkernel->askToGoOnline() )
331 return;
332 kmkernel->acctMgr()->checkMail( false );
335 QStringList KMKernel::accounts()
337 return kmkernel->acctMgr()->getAccounts();
340 void KMKernel::checkAccount( const QString &account ) //might create a new reader but won't show!!
342 kDebug(5006);
343 if ( account.isEmpty() )
344 checkMail();
345 else {
346 KMAccount* acct = kmkernel->acctMgr()->findByName( account );
347 if ( acct )
348 kmkernel->acctMgr()->singleCheckMail (acct, false );
352 void KMKernel::openReader( bool onlyCheck )
354 mWin = 0;
355 KMainWindow *ktmw = 0;
356 kDebug(5006);
358 foreach ( KMainWindow *window, KMainWindow::memberList() )
360 if ( ::qobject_cast<KMMainWin *>( window ) )
362 ktmw = window;
363 break;
367 bool activate;
368 if (ktmw) {
369 mWin = (KMMainWin *) ktmw;
370 activate = !onlyCheck; // existing window: only activate if not --check
371 if ( activate )
372 mWin->show();
374 else {
375 mWin = new KMMainWin;
376 mWin->show();
377 activate = false; // new window: no explicit activation (#73591)
380 if ( activate ) {
381 // Activate window - doing this instead of KWindowSystem::activateWindow(mWin->winId());
382 // so that it also works when called from KMailApplication::newInstance()
383 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
384 KStartupInfo::setNewStartupId( mWin, kapp->startupId() );
385 #endif
389 int KMKernel::openComposer( const QString &to, const QString &cc,
390 const QString &bcc, const QString &subject,
391 const QString &body, bool hidden,
392 const QString &messageFile,
393 const QStringList &attachmentPaths,
394 const QStringList &customHeaders )
396 kDebug(5006);
397 KMMessage *msg = new KMMessage;
398 msg->initHeader();
399 msg->setCharset("utf-8");
400 // tentatively decode to, cc and bcc because invokeMailer calls us with
401 // RFC 2047 encoded addresses in order to protect non-ASCII email addresses
402 if (!to.isEmpty())
403 msg->setTo( KMMsgBase::decodeRFC2047String( to.toLatin1() ) );
404 if (!cc.isEmpty())
405 msg->setCc( KMMsgBase::decodeRFC2047String( cc.toLatin1() ) );
406 if (!bcc.isEmpty())
407 msg->setBcc( KMMsgBase::decodeRFC2047String( bcc.toLatin1() ) );
408 if (!subject.isEmpty()) msg->setSubject(subject);
410 KUrl messageUrl = KUrl( messageFile );
411 if ( !messageUrl.isEmpty() && messageUrl.isLocalFile() ) {
412 QByteArray str = KPIMUtils::kFileToByteArray( messageUrl.path(), true, false );
413 if( !str.isEmpty() ) {
414 msg->setBody( QString::fromLocal8Bit( str.data(), str.size() ).toUtf8() );
416 else {
417 TemplateParser parser( msg, TemplateParser::NewMessage,
418 QString(), false, false, false );
419 parser.process( NULL, NULL );
422 else if ( !body.isEmpty() ) {
423 msg->setBody( body.toUtf8() );
425 else {
426 TemplateParser parser( msg, TemplateParser::NewMessage,
427 QString(), false, false, false );
428 parser.process( 0, 0 );
431 if ( !customHeaders.isEmpty() )
433 for ( QStringList::ConstIterator it = customHeaders.begin() ; it != customHeaders.end() ; ++it )
434 if ( !(*it).isEmpty() )
436 const int pos = (*it).indexOf( ':' );
437 if ( pos > 0 )
439 QString header = (*it).left( pos ).trimmed();
440 QString value = (*it).mid( pos+1 ).trimmed();
441 if ( !header.isEmpty() && !value.isEmpty() )
442 msg->setHeaderField( header.toUtf8(), value );
447 KMail::Composer * cWin = KMail::makeComposer( msg );
448 cWin->setCharset( "", true );
449 KUrl::List attachURLs = KUrl::List( attachmentPaths );
450 for ( KUrl::List::ConstIterator it = attachURLs.begin() ; it != attachURLs.end() ; ++it )
451 cWin->addAttach( (*it) );
452 if ( !hidden ) {
453 cWin->show();
454 // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
455 // so that it also works when called from KMailApplication::newInstance()
456 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
457 KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
458 #endif
460 return 1;
463 int KMKernel::openComposer (const QString &to, const QString &cc,
464 const QString &bcc, const QString &subject,
465 const QString &body, bool hidden,
466 const QString &attachName,
467 const QByteArray &attachCte,
468 const QByteArray &attachData,
469 const QByteArray &attachType,
470 const QByteArray &attachSubType,
471 const QByteArray &attachParamAttr,
472 const QString &attachParamValue,
473 const QByteArray &attachContDisp,
474 const QByteArray &attachCharset,
475 unsigned int identity )
477 kDebug(5006);
479 KMMessage *msg = new KMMessage;
480 KMMessagePart *msgPart = 0;
481 msg->initHeader();
482 msg->setCharset( "utf-8" );
483 if ( !cc.isEmpty() ) msg->setCc(cc);
484 if ( !bcc.isEmpty() ) msg->setBcc(bcc);
485 if ( !subject.isEmpty() ) msg->setSubject(subject);
486 if ( !to.isEmpty() ) msg->setTo(to);
487 if ( identity > 0 ) msg->setHeaderField( "X-KMail-Identity", QString::number( identity ) );
488 if ( !body.isEmpty() ) {
489 msg->setBody(body.toUtf8());
490 } else {
491 TemplateParser parser( msg, TemplateParser::NewMessage,
492 QString(), false, false, false );
493 parser.process( NULL, NULL );
496 bool iCalAutoSend = false;
497 bool noWordWrap = false;
498 bool isICalInvitation = false;
499 KConfigGroup options( config(), "Groupware" );
500 if ( !attachData.isEmpty() ) {
501 isICalInvitation = attachName == "cal.ics" &&
502 attachType == "text" &&
503 attachSubType == "calendar" &&
504 attachParamAttr == "method";
505 // Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
506 if ( isICalInvitation && bcc.isEmpty() )
507 msg->setBcc( "" );
508 if ( isICalInvitation &&
509 GlobalSettings::self()->legacyBodyInvites() ) {
510 // KOrganizer invitation caught and to be sent as body instead
511 msg->setBody( attachData );
512 msg->setHeaderField( "Content-Type",
513 QString( "text/calendar; method=%1; "
514 "charset=\"utf-8\"" ).
515 arg( attachParamValue ) );
517 iCalAutoSend = true; // no point in editing raw ICAL
518 noWordWrap = true; // we shant word wrap inline invitations
519 } else {
520 // Just do what we're told to do
521 msgPart = new KMMessagePart;
522 msgPart->setName( attachName );
523 msgPart->setCteStr( attachCte );
524 msgPart->setBodyEncoded( attachData );
525 msgPart->setTypeStr( attachType );
526 msgPart->setSubtypeStr( attachSubType );
527 msgPart->setParameter( attachParamAttr, attachParamValue );
528 if( ! GlobalSettings::self()->exchangeCompatibleInvitations() ) {
529 msgPart->setContentDisposition( attachContDisp );
531 if( !attachCharset.isEmpty() ) {
532 // kDebug(5006) << "Set attachCharset to" << attachCharset;
533 msgPart->setCharset( attachCharset );
535 // Don't show the composer window if the automatic sending is checked
536 iCalAutoSend = GlobalSettings::self()->automaticSending();
540 KMail::Composer * cWin = KMail::makeComposer();
541 cWin->setMsg( msg, !isICalInvitation /* mayAutoSign */ );
542 cWin->setSigningAndEncryptionDisabled( isICalInvitation
543 && GlobalSettings::self()->legacyBodyInvites() );
544 cWin->setAutoDelete( true );
545 if( noWordWrap )
546 cWin->disableWordWrap();
547 else
548 cWin->setCharset( "", true );
549 if ( msgPart )
550 cWin->addAttach(msgPart);
552 if ( !hidden && !iCalAutoSend ) {
553 cWin->show();
554 // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
555 // so that it also works when called from KMailApplication::newInstance()
556 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
557 KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
558 #endif
559 } else {
560 cWin->slotSendNow();
563 return 1;
566 void KMKernel::setDefaultTransport( const QString & transport )
568 MailTransport::Transport *t = MailTransport::TransportManager::self()->transportByName( transport, false );
569 if ( !t ) {
570 kWarning(5006) <<"The transport you entered is not available";
571 return;
573 MailTransport::TransportManager::self()->setDefaultTransport( t->id() );
576 QDBusObjectPath KMKernel::openComposer( const QString &to, const QString &cc,
577 const QString &bcc,
578 const QString &subject,
579 const QString &body, bool hidden )
581 KMMessage *msg = new KMMessage;
582 msg->initHeader();
583 msg->setCharset("utf-8");
584 if (!cc.isEmpty()) msg->setCc(cc);
585 if (!bcc.isEmpty()) msg->setBcc(bcc);
586 if (!subject.isEmpty()) msg->setSubject(subject);
587 if (!to.isEmpty()) msg->setTo(to);
588 if ( !body.isEmpty() ) {
589 msg->setBody(body.toUtf8());
590 } else {
591 TemplateParser parser( msg, TemplateParser::NewMessage,
592 QString(), false, false, false );
593 parser.process( NULL, NULL );
596 KMail::Composer * cWin = KMail::makeComposer( msg );
597 cWin->setCharset("", true);
598 if ( !hidden ) {
599 cWin->show();
600 // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
601 // so that it also works when called from KMailApplication::newInstance()
602 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
603 KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
604 #endif
607 return QDBusObjectPath(cWin->dbusObjectPath());
610 QDBusObjectPath KMKernel::newMessage( const QString &to,
611 const QString &cc,
612 const QString &bcc,
613 bool hidden,
614 bool useFolderId,
615 const QString & /*messageFile*/,
616 const QString &_attachURL)
618 KUrl attachURL( _attachURL );
619 KMMessage *msg = new KMMessage;
620 KMFolder *folder = 0;
621 uint id = 0;
623 if ( useFolderId ) {
624 //create message with required folder identity
625 folder = currentFolder();
626 id = folder ? folder->identity() : 0;
628 msg->initHeader( id );
629 msg->setCharset( "utf-8" );
630 //set basic headers
631 if ( !to.isEmpty() ) {
632 msg->setTo( to );
634 if ( !cc.isEmpty() ) {
635 msg->setCc( cc );
637 if ( !bcc.isEmpty() ) {
638 msg->setBcc( bcc );
641 TemplateParser parser( msg, TemplateParser::NewMessage,
642 QString(), false, false, false );
643 parser.process( NULL, folder );
645 KMail::Composer *win = makeComposer( msg, id );
647 //Add the attachment if we have one
648 if ( !attachURL.isEmpty() && attachURL.isValid() ) {
649 win->addAttach( attachURL );
652 //only show window when required
653 if ( !hidden ) {
654 win->show();
656 return QDBusObjectPath( win->dbusObjectPath() );
659 int KMKernel::viewMessage( const KUrl & messageFile )
661 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( 0, messageFile );
663 openCommand->start();
665 return 1;
668 int KMKernel::sendCertificate( const QString& to, const QByteArray& certData )
670 KMMessage *msg = new KMMessage;
671 msg->initHeader();
672 msg->setCharset("utf-8");
673 msg->setSubject( i18n( "Certificate Signature Request" ) );
674 if (!to.isEmpty()) msg->setTo(to);
675 // ### Make this message customizable via KIOSK
676 msg->setBody( i18n( "Please create a certificate from attachment and return to sender." ).toUtf8() );
678 KMail::Composer * cWin = KMail::makeComposer( msg );
679 cWin->setCharset("", true);
680 cWin->slotSetAlwaysSend( true );
681 if (!certData.isEmpty()) {
682 KMMessagePart *msgPart = new KMMessagePart;
683 msgPart->setName("smime.p10");
684 msgPart->setCteStr("base64");
685 msgPart->setBodyEncodedBinary(certData);
686 msgPart->setTypeStr("application");
687 msgPart->setSubtypeStr("pkcs10");
688 msgPart->setContentDisposition("attachment; filename=smime.p10");
689 cWin->addAttach(msgPart);
692 cWin->show();
693 return 1;
696 int KMKernel::dbusAddMessage( const QString & foldername,
697 const QString & messageFile,
698 const QString & MsgStatusFlags)
700 kDebug(5006);
702 if ( foldername.isEmpty() || foldername.startsWith('.'))
703 return -1;
705 int retval;
706 bool readFolderMsgIds = false;
707 QString _foldername = foldername.trimmed();
708 _foldername = _foldername.remove( '\\' ); //try to prevent ESCAPE Sequences
710 if ( foldername != mAddMessageLastFolder ) {
711 mAddMessageMsgIds.clear();
712 readFolderMsgIds = true;
713 mAddMessageLastFolder = foldername;
716 KUrl msgUrl( messageFile );
717 if ( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) {
719 const QByteArray messageText =
720 KPIMUtils::kFileToByteArray( msgUrl.path(), true, false );
721 if ( messageText.isEmpty() )
722 return -2;
724 KMMessage *msg = new KMMessage();
725 msg->fromString( messageText );
727 if (readFolderMsgIds) {
728 if ( foldername.contains("/")) {
729 QString tmp_fname = "";
730 KMFolder *folder = NULL;
731 KMFolderDir *subfolder;
732 bool root = true;
734 QStringList subFList = _foldername.split('/', QString::SkipEmptyParts);
736 for ( QStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
737 QString _newFolder = *it;
738 if(_newFolder.startsWith('.')) return -1;
740 if(root) {
741 folder = the_folderMgr->findOrCreate(*it, false);
742 if (folder) {
743 root = false;
744 tmp_fname = '/' + *it;
746 else return -1;
748 else {
749 subfolder = folder->createChildFolder();
750 tmp_fname += '/' + *it;
751 if(!the_folderMgr->getFolderByURL( tmp_fname )) {
752 folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder);
755 if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
759 mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
760 if(!folder) return -1;
763 else {
764 mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
768 if ( mAddMsgCurrentFolder ) {
769 if (readFolderMsgIds) {
771 // OLD COMMENT:
772 // Try to determine if a message already exists in
773 // the folder. The message id that is searched for, is
774 // the subject line + the date. This should be quite
775 // unique. The change that a given date with a given
776 // subject is in the folder twice is very small.
777 // If the subject is empty, the fromStrip string
778 // is taken.
780 // NEW COMMENT from Danny Kukawka (danny.kukawka@web.de):
781 // subject line + the date is only unique if the following
782 // return a correct unique value:
783 // time_t DT = mb->date();
784 // QString dt = ctime(&DT);
785 // But if the datestring in the Header isn't RFC conform
786 // subject line + the date isn't unique.
788 // The only uique headerfield is the Message-ID. In some
789 // cases this could be empty. I then I use the
790 // subject line + dateStr .
792 int i;
794 mAddMsgCurrentFolder->open( "dbusadd" );
795 for( i=0; i<mAddMsgCurrentFolder->count(); i++) {
796 KMMsgBase *mb = mAddMsgCurrentFolder->getMsgBase(i);
797 QString id = mb->msgIdMD5();
798 if ( id.isEmpty() ) {
799 id = mb->subject();
800 if ( id.isEmpty() )
801 id = mb->fromStrip();
802 if ( id.isEmpty() )
803 id = mb->toStrip();
805 id += mb->dateStr();
808 //fprintf(stderr,"%s\n",(const char *) id);
809 if ( !id.isEmpty() ) {
810 mAddMessageMsgIds.append(id);
813 mAddMsgCurrentFolder->close( "dbusadd" );
816 QString msgId = msg->msgIdMD5();
817 if ( msgId.isEmpty()) {
818 msgId = msg->subject();
819 if ( msgId.isEmpty() )
820 msgId = msg->fromStrip();
821 if ( msgId.isEmpty() )
822 msgId = msg->toStrip();
824 msgId += msg->dateStr();
827 int k = mAddMessageMsgIds.indexOf( msgId );
828 //fprintf(stderr,"find %s = %d\n",(const char *) msgId,k);
830 if ( k == -1 ) {
831 if ( !msgId.isEmpty() ) {
832 mAddMessageMsgIds.append( msgId );
835 if ( !MsgStatusFlags.isEmpty() ) {
836 msg->status().setStatusFromStr(MsgStatusFlags);
839 int index;
840 if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
841 mAddMsgCurrentFolder->unGetMsg( index );
842 retval = 1;
843 } else {
844 retval =- 2;
845 delete msg;
846 msg = 0;
848 } else {
849 //qDebug( "duplicate: " + msgId + "; subj: " + msg->subject() + ", from: " + msgId = msg->fromStrip());
850 retval = -4;
852 } else {
853 retval = -1;
855 } else {
856 retval = -2;
858 return retval;
861 void KMKernel::dbusResetAddMessage()
863 mAddMessageMsgIds.clear();
864 mAddMessageLastFolder.clear();
867 int KMKernel::dbusAddMessage_fastImport( const QString & foldername,
868 const QString & messageFile,
869 const QString & MsgStatusFlags)
871 // Use this function to import messages without
872 // search for already existing emails.
873 kDebug(5006);
875 if ( foldername.isEmpty() || foldername.startsWith('.'))
876 return -1;
878 int retval;
879 bool createNewFolder = false;
881 QString _foldername = foldername.trimmed();
882 _foldername = _foldername.remove( '\\' ); //try to prevent ESCAPE Sequences
884 if ( foldername != mAddMessageLastFolder ) {
885 createNewFolder = true;
886 mAddMessageLastFolder = foldername;
889 KUrl msgUrl( messageFile );
890 if ( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) {
891 const QByteArray messageText =
892 KPIMUtils::kFileToByteArray( msgUrl.path(), true, false );
893 if ( messageText.isEmpty() )
894 return -2;
896 KMMessage *msg = new KMMessage();
897 msg->fromString( messageText );
899 if (createNewFolder) {
900 if ( foldername.contains("/")) {
901 QString tmp_fname = "";
902 KMFolder *folder = NULL;
903 KMFolderDir *subfolder;
904 bool root = true;
906 QStringList subFList = _foldername.split('/', QString::SkipEmptyParts);
908 for ( QStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
909 QString _newFolder = *it;
910 if(_newFolder.startsWith('.')) return -1;
912 if(root) {
913 folder = the_folderMgr->findOrCreate(*it, false);
914 if (folder) {
915 root = false;
916 tmp_fname = '/' + *it;
918 else return -1;
920 else {
921 subfolder = folder->createChildFolder();
922 tmp_fname += '/' + *it;
923 if(!the_folderMgr->getFolderByURL( tmp_fname )) {
924 folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder);
926 if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
930 mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
931 if(!folder) return -1;
934 else {
935 mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
939 if ( mAddMsgCurrentFolder ) {
940 int index;
942 if( !MsgStatusFlags.isEmpty() ) {
943 msg->status().setStatusFromStr(MsgStatusFlags);
946 if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
947 mAddMsgCurrentFolder->unGetMsg( index );
948 retval = 1;
949 } else {
950 retval =- 2;
951 delete msg;
952 msg = 0;
954 } else {
955 retval = -1;
957 } else {
958 retval = -2;
961 return retval;
964 QStringList KMKernel::folderList() const
966 QStringList folders;
967 const QString localPrefix = "/Local";
968 folders << localPrefix;
969 the_folderMgr->getFolderURLS( folders, localPrefix );
970 the_imapFolderMgr->getFolderURLS( folders );
971 the_dimapFolderMgr->getFolderURLS( folders );
972 return folders;
975 QString KMKernel::getFolder( const QString& vpath )
977 QString adaptorName;
978 const QString localPrefix = "/Local";
979 if ( the_folderMgr->getFolderByURL( vpath ) )
980 adaptorName=vpath;
981 else if ( vpath.startsWith( localPrefix ) && the_folderMgr->getFolderByURL( vpath.mid( localPrefix.length() ) ) )
982 adaptorName=vpath.mid( localPrefix.length() );
983 else if ( the_imapFolderMgr->getFolderByURL( vpath ) )
984 adaptorName=vpath;
985 else if (the_dimapFolderMgr->getFolderByURL( vpath ) )
986 adaptorName=vpath;
987 if( !adaptorName.isEmpty())
989 if ( folderAdaptor )
991 folderAdaptor->unregisterobject();
992 delete folderAdaptor;
994 folderAdaptor = new KMail::FolderAdaptor(adaptorName);
995 return vpath;
997 kWarning(5006) << "Folder not found:" << vpath;
998 return QString();
1001 void KMKernel::raise()
1003 QDBusInterface iface( KMAIL_DBUS_SERVICE, "/MainApplication",
1004 "org.kde.KUniqueApplication",
1005 QDBusConnection::sessionBus());
1006 QDBusReply<int> reply;
1007 if ( !iface.isValid() || !( reply = iface.call( "newInstance" ) ).isValid() )
1009 QDBusError err = iface.lastError();
1010 kError() << "Communication problem with KMail. "
1011 << "Error message was:" << err.name() << ": \"" << err.message() << "\"";
1016 bool KMKernel::showMail( quint32 serialNumber, const QString& /* messageId */ )
1018 KMMainWidget *mainWidget = 0;
1020 // First look for a KMainWindow.
1021 foreach ( KMainWindow* window, KMainWindow::memberList() ) {
1022 // Then look for a KMMainWidget.
1023 QList<KMMainWidget*> l = window->findChildren<KMMainWidget*>();
1024 if ( !l.isEmpty() && l.first() ) {
1025 mainWidget = l.first();
1026 if ( window->isActiveWindow() )
1027 break;
1031 if ( mainWidget ) {
1032 int idx = -1;
1033 KMFolder *folder = 0;
1034 KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
1035 if (!folder || (idx == -1))
1036 return false;
1037 KMFolderOpener openFolder(folder, "showmail");
1038 KMMsgBase *msgBase = folder->getMsgBase(idx);
1039 if (!msgBase)
1040 return false;
1041 bool unGet = !msgBase->isMessage();
1042 KMMessage *msg = folder->getMsg(idx);
1044 KMReaderMainWin *win = new KMReaderMainWin( false, false );
1045 KMMessage *newMessage = new KMMessage( *msg );
1046 newMessage->setParent( msg->parent() );
1047 newMessage->setMsgSerNum( msg->getMsgSerNum() );
1048 newMessage->setReadyToShow( true );
1049 win->showMsg( GlobalSettings::self()->overrideCharacterEncoding(), newMessage );
1050 win->show();
1052 if (unGet)
1053 folder->unGetMsg(idx);
1054 return true;
1057 return false;
1060 QString KMKernel::getFrom( quint32 serialNumber )
1062 int idx = -1;
1063 KMFolder *folder = 0;
1064 KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
1065 if (!folder || (idx == -1))
1066 return QString();
1067 KMFolderOpener openFolder(folder, "getFrom");
1068 KMMsgBase *msgBase = folder->getMsgBase(idx);
1069 if (!msgBase)
1070 return QString();
1071 bool unGet = !msgBase->isMessage();
1072 KMMessage *msg = folder->getMsg(idx);
1073 QString result = msg->from();
1074 if (unGet)
1075 folder->unGetMsg(idx);
1076 return result;
1079 QString KMKernel::debugScheduler()
1081 QString res = KMail::ActionScheduler::debug();
1082 return res;
1085 QString KMKernel::debugSernum( quint32 serialNumber )
1087 QString res;
1088 if (serialNumber != 0) {
1089 int idx = -1;
1090 KMFolder *folder = 0;
1091 KMMsgBase *msg = 0;
1092 KMMsgDict::instance()->getLocation( serialNumber, &folder, &idx );
1093 // It's possible that the message has been deleted or moved into a
1094 // different folder
1095 if (folder && (idx != -1)) {
1096 // everything is ok
1097 KMFolderOpener openFolder( folder, "debugser" );
1098 msg = folder->getMsgBase( idx );
1099 if (msg) {
1100 res.append( QString( " subject %s,\n sender %s,\n date %s.\n" )
1101 .arg( msg->subject() )
1102 .arg( msg->fromStrip() )
1103 .arg( msg->dateStr() ) );
1104 } else {
1105 res.append( QString( "Invalid serial number." ) );
1107 } else {
1108 res.append( QString( "Invalid serial number." ) );
1111 return res;
1115 void KMKernel::pauseBackgroundJobs()
1117 mBackgroundTasksTimer->stop();
1118 mJobScheduler->pause();
1121 void KMKernel::resumeBackgroundJobs()
1123 mJobScheduler->resume();
1124 mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000 );
1127 void KMKernel::stopNetworkJobs()
1129 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
1130 return;
1132 GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Offline );
1133 BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended"));
1134 emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
1138 void KMKernel::resumeNetworkJobs()
1140 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online )
1141 return;
1143 GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Online );
1144 BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed"));
1145 emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
1147 if ( kmkernel->msgSender()->sendImmediate() ) {
1148 kmkernel->msgSender()->sendQueued();
1152 bool KMKernel::isOffline()
1154 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
1155 return true;
1156 else
1157 return false;
1160 bool KMKernel::askToGoOnline()
1162 if ( kmkernel->isOffline() ) {
1163 int rc =
1164 KMessageBox::questionYesNo( KMKernel::self()->mainWin(),
1165 i18n("KMail is currently in offline mode. "
1166 "How do you want to proceed?"),
1167 i18n("Online/Offline"),
1168 KGuiItem(i18n("Work Online")),
1169 KGuiItem(i18n("Work Offline")));
1171 if( rc == KMessageBox::No ) {
1172 return false;
1173 } else {
1174 kmkernel->resumeNetworkJobs();
1177 return true;
1180 /********************************************************************/
1181 /* Kernel methods */
1182 /********************************************************************/
1184 void KMKernel::quit()
1186 // Called when all windows are closed. Will take care of compacting,
1187 // sending... should handle session management too!!
1189 /* TODO later:
1190 Asuming that:
1191 - msgsender is nonblocking
1192 (our own, QSocketNotifier based. Pops up errors and sends signal
1193 senderFinished when done)
1195 o If we are getting mail, stop it (but don't lose something!)
1196 [Done already, see mailCheckAborted]
1197 o If we are sending mail, go on UNLESS this was called by SM,
1198 in which case stop ASAP that too (can we warn? should we continue
1199 on next start?)
1200 o If we are compacting, or expunging, go on UNLESS this was SM call.
1201 In that case stop compacting ASAP and continue on next start, before
1202 touching any folders. [Not needed anymore with CompactionJob]
1204 KMKernel::quit ()
1206 SM call?
1207 if compacting, stop;
1208 if sending, stop;
1209 if receiving, stop;
1210 Windows will take care of themselves (composer should dump
1211 its messages, if any but not in deadMail)
1212 declare us ready for the End of the Session
1214 No, normal quit call
1215 All windows are off. Anything to do, should compact or sender sends?
1216 Yes, maybe put an icon in panel as a sign of life
1217 if sender sending, connect us to his finished slot, declare us ready
1218 for quit and wait for senderFinished
1219 if not, Folder manager, go compact sent-mail and outbox
1220 } (= call slotFinished())
1222 void KMKernel::slotSenderFinished()
1224 good, Folder manager go compact sent-mail and outbox
1225 clean up stage1 (release folders and config, unregister from dcop)
1226 -- another kmail may start now ---
1227 qApp->quit();
1232 /********************************************************************/
1233 /* Init, Exit, and handler methods */
1234 /********************************************************************/
1235 void KMKernel::testDir( const char *_name )
1237 QString foldersPath = QDir::homePath() + QString( _name );
1238 QFileInfo info( foldersPath );
1239 if ( !info.exists() ) {
1240 if ( KDE_mkdir( QFile::encodeName( foldersPath ), S_IRWXU ) == -1 ) {
1241 KMessageBox::sorry( 0, i18n( "KMail could not create folder '%1';\n"
1242 "please make sure that you can view and "
1243 "modify the content of the folder '%2'.",
1244 foldersPath, QDir::homePath() ) );
1245 ::exit(-1);
1248 if ( !info.isDir() || !info.isReadable() || !info.isWritable() ) {
1249 KMessageBox::sorry( 0, i18n( "The permissions of the folder '%1' are "
1250 "incorrect;\n"
1251 "please make sure that you can view and "
1252 "modify the content of this folder.",
1253 foldersPath ) );
1254 ::exit(-1);
1259 //-----------------------------------------------------------------------------
1260 // Open a composer for each message found in the dead.letter folder
1261 void KMKernel::recoverDeadLetters()
1263 const QString pathName = localDataPath();
1264 QDir dir( pathName );
1265 if ( !dir.exists( "autosave" ) )
1266 return;
1268 KMFolder folder( 0, pathName + "autosave", KMFolderTypeMaildir, false /* no index */ );
1269 KMFolderOpener openFolder( &folder, "recover" );
1270 if ( !folder.isOpened() ) {
1271 perror( "cannot open autosave folder" );
1272 return;
1275 const int num = folder.count();
1276 for ( int i = 0; i < num; i++ ) {
1277 KMMessage *msg = folder.take( 0 );
1278 if ( msg ) {
1279 KMail::Composer * win = KMail::makeComposer();
1280 win->setMsg( msg, false, false, true );
1281 win->setAutoSaveFilename( msg->fileName() );
1282 win->show();
1287 //-----------------------------------------------------------------------------
1288 void KMKernel::initFolders(KConfig* cfg)
1290 QString name;
1291 KConfigGroup group(cfg,"General");
1293 name = group.readEntry("inboxFolder");
1295 // Currently the folder manager cannot manage folders which are not
1296 // in the base folder directory.
1297 //if (name.isEmpty()) name = getenv("MAIL");
1299 if (name.isEmpty()) name = I18N_NOOP("inbox");
1301 the_inboxFolder = (KMFolder*)the_folderMgr->findOrCreate(name);
1303 if ( !the_inboxFolder->canAccess() ) {
1304 emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
1307 the_inboxFolder->setSystemFolder(true);
1308 if ( the_inboxFolder->userWhoField().isEmpty() )
1309 the_inboxFolder->setUserWhoField( QString() );
1310 // inboxFolder->open();
1312 the_outboxFolder = the_folderMgr->findOrCreate(group.readEntry("outboxFolder", I18N_NOOP("outbox")));
1313 if ( !the_outboxFolder->canAccess() ) {
1314 emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
1316 the_outboxFolder->setNoChildren(true);
1318 the_outboxFolder->setSystemFolder(true);
1319 if ( the_outboxFolder->userWhoField().isEmpty() )
1320 the_outboxFolder->setUserWhoField( QString() );
1321 /* Nuke the oubox's index file, to make sure that no ghost messages are in
1322 * it from a previous crash. Ghost messages happen in the outbox because it
1323 * the only folder where messages enter and leave within 5 seconds, which is
1324 * the leniency period for index invalidation. Since the number of mails in
1325 * this folder is expected to be very small, we can live with regenerating
1326 * the index on each start to be on the save side. */
1327 //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir )
1328 // unlink( QFile::encodeName( the_outboxFolder->indexLocation() ) );
1329 the_outboxFolder->open( "kmkernel" );
1331 the_sentFolder = the_folderMgr->findOrCreate(group.readEntry("sentFolder", I18N_NOOP("sent-mail")));
1332 if ( !the_sentFolder->canAccess() ) {
1333 emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
1335 the_sentFolder->setSystemFolder(true);
1336 if ( the_sentFolder->userWhoField().isEmpty() )
1337 the_sentFolder->setUserWhoField( QString() );
1338 // the_sentFolder->open();
1340 the_trashFolder = the_folderMgr->findOrCreate(group.readEntry("trashFolder", I18N_NOOP("trash")));
1341 if ( !the_trashFolder->canAccess() ) {
1342 emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
1344 the_trashFolder->setSystemFolder(true);
1345 if ( the_trashFolder->userWhoField().isEmpty() )
1346 the_trashFolder->setUserWhoField( QString() );
1347 // the_trashFolder->open();
1349 the_draftsFolder = the_folderMgr->findOrCreate(group.readEntry("draftsFolder", I18N_NOOP("drafts")));
1350 if ( !the_draftsFolder->canAccess() ) {
1351 emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
1353 the_draftsFolder->setSystemFolder(true);
1354 if ( the_draftsFolder->userWhoField().isEmpty() )
1355 the_draftsFolder->setUserWhoField( QString() );
1356 the_draftsFolder->open( "kmkernel" );
1358 the_templatesFolder = the_folderMgr->findOrCreate(group.readEntry("templatesFolder", I18N_NOOP("templates")));
1359 if ( !the_templatesFolder->canAccess() ) {
1360 emergencyExit( i18n("You do not have read/write permission to your templates folder.") );
1362 the_templatesFolder->setSystemFolder(true);
1363 if ( the_templatesFolder->userWhoField().isEmpty() )
1364 the_templatesFolder->setUserWhoField( QString() );
1365 the_templatesFolder->open( "kmkernel" );
1369 void KMKernel::init()
1371 the_shuttingDown = false;
1372 the_server_is_ready = false;
1374 KConfig* cfg = KMKernel::config();
1376 QDir dir;
1378 KConfigGroup group(cfg, "General");
1379 the_firstStart = group.readEntry("first-start", true );
1380 group.writeEntry("first-start", false);
1381 the_previousVersion = group.readEntry("previous-version");
1382 group.writeEntry("previous-version", KMAIL_VERSION);
1384 QString foldersPath = group.readPathEntry( "folders", QString() );
1385 QString standardFolderPath = localDataPath() + "mail";
1386 kDebug() << "foldersPath (from config):" << foldersPath;
1388 if ( foldersPath.isEmpty() ) {
1389 foldersPath = standardFolderPath;
1390 if ( transferMail( foldersPath ) ) {
1391 group.writePathEntry( "folders", foldersPath );
1393 kDebug() << "foldersPath (after transferMail):" << foldersPath;
1395 else {
1396 // Check if the folder path from config really exists.
1397 // When migrating from KDE3 to KDE4, some distros change the home directory
1398 // from .kde to .kde4, and if the user has copied the config file + app data
1399 // over to .kde4, the config file then contains the incorrect entry.
1400 // Therefore, we fall back to KDEHOME/share/apps/kmail/mail if the folders
1401 // can't be found.
1402 QDir configFolderDir( foldersPath );
1403 if ( foldersPath.contains( ".kde/share/apps/kmail/mail" ) &&
1404 !configFolderDir.exists() ) {
1405 QDir standardConfigDir( standardFolderPath );
1406 if ( standardConfigDir.exists() ) {
1407 foldersPath = standardFolderPath;
1408 kDebug() << "foldersPath from config doesn't exist, using standard "
1409 "path instead";
1414 //Here because folderMgr's need it when they read the index and sort tags
1415 the_msgTagMgr = new KMMessageTagMgr();
1416 the_msgTagMgr->readConfig();
1418 // moved up here because KMMessage::stripOffPrefixes is used below
1419 KMMessage::readConfig();
1421 the_undoStack = new UndoStack(20);
1422 the_folderMgr = new KMFolderMgr(foldersPath);
1423 the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
1424 the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
1426 the_searchFolderMgr = new KMFolderMgr(KStandardDirs::locateLocal("data","kmail/search"), KMSearchDir);
1427 KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
1428 if (lsf)
1429 the_searchFolderMgr->remove( lsf );
1431 the_acctMgr = new AccountManager();
1432 the_filterMgr = new KMFilterMgr();
1433 the_popFilterMgr = new KMFilterMgr(true);
1434 the_filterActionDict = new KMFilterActionDict;
1436 initFolders(cfg);
1437 the_acctMgr->readConfig();
1438 the_filterMgr->readConfig();
1439 the_popFilterMgr->readConfig();
1440 cleanupImapFolders();
1442 the_msgSender = new KMSender;
1443 the_server_is_ready = true;
1444 { // area for config group "Composer"
1445 KConfigGroup group(cfg, "Composer");
1446 if (group.readEntry("pref-charsets", QStringList() ).isEmpty())
1448 group.writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
1451 readConfig();
1452 // filterMgr->dump();
1454 the_weaver = new ThreadWeaver::Weaver( this );
1456 connect( the_folderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1457 this, SIGNAL( folderRemoved(KMFolder*) ) );
1458 connect( the_dimapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1459 this, SIGNAL( folderRemoved(KMFolder*) ) );
1460 connect( the_imapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1461 this, SIGNAL( folderRemoved(KMFolder*) ) );
1462 connect( the_searchFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
1463 this, SIGNAL( folderRemoved(KMFolder*) ) );
1465 mBackgroundTasksTimer = new QTimer( this );
1466 mBackgroundTasksTimer->setSingleShot( true );
1467 connect( mBackgroundTasksTimer, SIGNAL( timeout() ), this, SLOT( slotRunBackgroundTasks() ) );
1468 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
1469 mBackgroundTasksTimer->start( 10000 ); // 10s, singleshot
1470 #else
1471 mBackgroundTasksTimer->start( 5 * 60000 ); // 5 minutes, singleshot
1472 #endif
1475 void KMKernel::readConfig()
1477 //Needed here, since this function is also called when the configuration
1478 //changes, and the static variables should be updated then - IOF
1479 KMMessage::readConfig();
1482 void KMKernel::cleanupImapFolders()
1484 KMAccount *acct = 0;
1485 QList<KMFolderNode*>::iterator it = the_imapFolderMgr->dir().begin();
1486 while ( it != the_imapFolderMgr->dir().end() )
1488 KMFolderNode *node = *it;
1489 if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
1490 && ( acct->type() == KAccount::Imap ))
1491 || !the_acctMgr->isEnabled( node->id() ))
1493 ++it;
1494 } else {
1495 KMFolder* folder = static_cast<KMFolder*>(node);
1496 // delete only local
1497 static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true );
1498 the_imapFolderMgr->remove(folder);
1499 it = the_imapFolderMgr->dir().begin();
1503 it = the_dimapFolderMgr->dir().begin();
1504 while ( it != the_dimapFolderMgr->dir().end() )
1506 KMFolderNode *node = *it;
1507 if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
1508 && ( acct->type() == KAccount::DImap )) )
1510 ++it;
1511 } else {
1512 the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
1513 it = the_dimapFolderMgr->dir().begin();
1517 the_imapFolderMgr->quiet(true);
1518 QList<KMAccount*>::iterator accountIt = the_acctMgr->begin();
1519 while ( accountIt != the_acctMgr->end() ) {
1520 acct = *accountIt;
1521 ++accountIt;
1522 KMFolderImap *fld;
1523 KMAcctImap *imapAcct;
1525 if (acct->type() != KAccount::Imap)
1526 continue;
1527 fld = static_cast<KMFolderImap*>(the_imapFolderMgr
1528 ->findOrCreate(QString::number(acct->id()), false, acct->id())->storage());
1529 fld->setNoContent(true);
1530 fld->folder()->setLabel(acct->name());
1531 imapAcct = static_cast<KMAcctImap*>(acct);
1532 fld->setAccount(imapAcct);
1533 imapAcct->setImapFolder(fld);
1534 fld->close( "kernel", true );
1536 the_imapFolderMgr->quiet(false);
1538 the_dimapFolderMgr->quiet( true );
1539 accountIt = the_acctMgr->begin();
1540 while ( accountIt != the_acctMgr->end() ) {
1541 acct = *accountIt;
1542 ++accountIt;
1544 KMFolderCachedImap *cfld = 0;
1545 KMAcctCachedImap *cachedImapAcct;
1547 if (acct->type() != KAccount::DImap ) continue;
1549 KMFolder* fld = the_dimapFolderMgr->find(QString::number(acct->id()));
1550 if( fld )
1551 cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
1552 if (cfld == 0) {
1553 // Folder doesn't exist yet
1554 cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(QString::number(acct->id()),
1555 false, KMFolderTypeCachedImap)->storage());
1556 if (!cfld) {
1557 KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.", acct->name(), the_dimapFolderMgr->basePath())));
1558 exit(-1);
1560 cfld->folder()->setId( acct->id() );
1563 cfld->setNoContent(true);
1564 cfld->folder()->setLabel(acct->name());
1565 cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
1566 cfld->setAccount(cachedImapAcct);
1567 cachedImapAcct->setImapFolder(cfld);
1568 cfld->close( "kmkernel" );
1570 the_dimapFolderMgr->quiet( false );
1573 bool KMKernel::doSessionManagement()
1576 // Do session management
1577 if (kapp->isSessionRestored()){
1578 int n = 1;
1579 while (KMMainWin::canBeRestored(n)){
1580 //only restore main windows! (Matthias);
1581 if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
1582 (new KMMainWin)->restore(n);
1583 n++;
1585 return true; // we were restored by SM
1587 return false; // no, we were not restored
1590 void KMKernel::closeAllKMailWindows()
1592 QList<KMainWindow*> windowsToDelete;
1594 foreach ( KMainWindow* window, KMainWindow::memberList() ) {
1595 if ( ::qobject_cast<KMMainWin *>(window) ||
1596 ::qobject_cast<KMail::SecondaryWindow *>(window) )
1598 // close and delete the window
1599 window->setAttribute(Qt::WA_DeleteOnClose);
1600 window->close();
1601 windowsToDelete.append( window );
1605 // We delete all main windows here. Above we called close(), but that calls
1606 // deleteLater() internally, therefore does not delete it immediately.
1607 // This would lead to problems when closing Kontact when a composer window
1608 // is open, because the destruction order is:
1610 // 1. destructor of the Kontact mainwinow
1611 // 2. delete all parts
1612 // 3. the KMail part destructor calls KMKernel::cleanup(), which calls
1613 // this function
1614 // 4. delete all other mainwindows
1616 // Deleting the composer windows here will make sure that step 4 will not delete
1617 // any composer window, which would fail because the kernel is already deleted.
1618 qDeleteAll( windowsToDelete );
1619 windowsToDelete.clear();
1622 void KMKernel::cleanup(void)
1624 dumpDeadLetters();
1625 the_shuttingDown = true;
1626 closeAllKMailWindows();
1628 // Write the config while all other managers are alive
1629 the_acctMgr->writeConfig(false);
1630 delete the_filterMgr;
1631 the_filterMgr = 0;
1632 delete the_msgSender;
1633 the_msgSender = 0;
1634 delete the_filterActionDict;
1635 the_filterActionDict = 0;
1636 delete the_msgTagMgr;
1637 the_msgTagMgr = 0;
1638 delete the_undoStack;
1639 the_undoStack = 0;
1640 delete the_popFilterMgr;
1641 the_popFilterMgr = 0;
1643 delete the_weaver;
1644 the_weaver = 0;
1646 KConfig* config = KMKernel::config();
1647 KConfigGroup group(config, "General");
1649 if ( the_trashFolder ) {
1651 the_trashFolder->close( "kmkernel", true );
1653 if ( group.readEntry( "empty-trash-on-exit", false ) ) {
1654 if ( the_trashFolder->count( true ) > 0 ) {
1655 the_trashFolder->expunge();
1660 if ( mICalIface )
1661 mICalIface->cleanup();
1663 QList<QPointer<KMFolder> > folders;
1664 QStringList strList;
1665 KMFolder *folder;
1666 the_folderMgr->createFolderList(&strList, &folders);
1668 QList<QPointer<KMFolder> >::const_iterator it;
1669 for ( it = folders.begin(); it != folders.end(); ++it ) {
1670 folder = *it;
1671 if ( !folder || folder->isDir() ) {
1672 continue;
1674 folder->close( "kmkernel", true );
1676 strList.clear();
1677 folders.clear();
1678 the_searchFolderMgr->createFolderList(&strList, &folders);
1679 for ( it = folders.begin(); it != folders.end(); ++it ) {
1680 folder = *it;
1681 if ( !folder || folder->isDir() ) {
1682 continue;
1684 folder->close( "kmkernel", true );
1687 delete the_folderMgr;
1688 the_folderMgr = 0;
1689 delete the_imapFolderMgr;
1690 the_imapFolderMgr = 0;
1691 delete the_dimapFolderMgr;
1692 the_dimapFolderMgr = 0;
1693 // Delete the_acctMgr here since it is used in the other *Mgrs above.
1694 delete the_acctMgr;
1695 the_acctMgr = 0;
1696 delete the_searchFolderMgr;
1697 the_searchFolderMgr = 0;
1698 delete mConfigureDialog;
1699 mConfigureDialog = 0;
1700 // do not delete, because mWin may point to an existing window
1701 // delete mWin;
1702 mWin = 0;
1704 if ( RecentAddresses::exists() )
1705 RecentAddresses::self( config )->save( config );
1706 config->sync();
1709 bool KMKernel::transferMail( QString & destinationDir )
1711 QString dir;
1713 // check whether the user has a ~/KMail folder
1714 QFileInfo fi( QDir::home(), "KMail" );
1715 if ( fi.exists() && fi.isDir() ) {
1716 dir = QDir::homePath() + "/KMail";
1717 // the following two lines can be removed once moving mail is reactivated
1718 destinationDir = dir;
1719 return true;
1722 if ( dir.isEmpty() ) {
1723 // check whether the user has a ~/Mail folder
1724 fi.setFile( QDir::home(), "Mail" );
1725 if ( fi.exists() && fi.isDir() &&
1726 QFile::exists( QDir::homePath() + "/Mail/.inbox.index" ) ) {
1727 // there's a ~/Mail folder which seems to be used by KMail (because of the
1728 // index file)
1729 dir = QDir::homePath() + "/Mail";
1730 // the following two lines can be removed once moving mail is reactivated
1731 destinationDir = dir;
1732 return true;
1736 if ( dir.isEmpty() ) {
1737 return true; // there's no old mail folder
1740 #if 0
1741 // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved)
1742 const QString kmailName = KGlobal::mainComponent().aboutData()()->programName();
1743 QString msg;
1744 if ( KIO::NetAccess::exists( destinationDir, KIO::NetAccess::SourceSide, 0 ) ) {
1745 // if destinationDir exists, we need to warn about possible
1746 // overwriting of files. otherwise, we don't have to
1747 msg = ki18nc( "%1-%3 is the application name, %4-%7 are folder path",
1748 "<qt>The <i>%4</i> folder exists. "
1749 "%1 now uses the <i>%5</i> folder for "
1750 "its messages.<p>"
1751 "%2 can move the contents of <i>%6</i> into this folder for "
1752 "you, though this may replace any existing files with "
1753 "the same name in <i>%7</i>.</p><p>"
1754 "<strong>Would you like %3 to move the mail "
1755 "files now?</strong></p></qt>" )
1756 .subs( kmailName ).subs( kmailName ).subs( kmailName )
1757 .subs( dir ).subs( destinationDir ).subs( dir ).subs( destinationDir )
1758 .toString();
1760 else {
1761 msg = ki18nc( "%1-%3 is the application name, %4-%6 are folder path",
1762 "<qt>The <i>%4</i> folder exists. "
1763 "%1 now uses the <i>%5</i> folder for "
1764 "its messages. %2 can move the contents of <i>%6</i> into "
1765 "this folder for you.<p>"
1766 "<strong>Would you like %3 to move the mail "
1767 "files now?</strong></p></qt>" )
1768 .subs( kmailName ).subs( kmailName ).subs( kmailName )
1769 .subs( dir ).subs( destinationDir ).subs( dir )
1770 .toString();
1772 QString title = i18n( "Migrate Mail Files?" );
1773 QString buttonText = i18n( "Move" );
1775 if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) ==
1776 KMessageBox::No ) {
1777 destinationDir = dir;
1778 return true;
1781 if ( !KIO::NetAccess::move( dir, destinationDir ) ) {
1782 kDebug(5006) <<"Moving" << dir <<" to" << destinationDir <<" failed:" << KIO::NetAccess::lastErrorString();
1783 kDebug(5006) <<"Deleting" << destinationDir;
1784 KIO::NetAccess::del( destinationDir, 0 );
1785 destinationDir = dir;
1786 return false;
1788 #endif
1790 return true;
1795 void KMKernel::dumpDeadLetters()
1797 if ( shuttingDown() )
1798 return; //All documents should be saved before shutting down is set!
1800 // make all composer windows autosave their contents
1801 foreach ( KMainWindow* window, KMainWindow::memberList() ) {
1802 if ( KMail::Composer * win = ::qobject_cast<KMail::Composer*>( window ) ) {
1803 win->autoSaveMessage();
1804 // saving the message has to be finished right here, we are called from a dtor,
1805 // therefore we have no chance to finish this later
1806 // yes, this is ugly and potentially dangerous, but the alternative is losing
1807 // currently composed messages...
1808 while ( win->isComposing() )
1809 qApp->processEvents();
1816 void KMKernel::action( bool mailto, bool check, const QString &to,
1817 const QString &cc, const QString &bcc,
1818 const QString &subj, const QString &body,
1819 const KUrl &messageFile,
1820 const KUrl::List &attachURLs,
1821 const QStringList &customHeaders )
1823 if ( mailto )
1824 openComposer( to, cc, bcc, subj, body, 0,
1825 messageFile.pathOrUrl(), attachURLs.toStringList(),
1826 customHeaders );
1827 else
1828 openReader( check );
1830 if ( check )
1831 checkMail();
1832 //Anything else?
1835 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KUrl &aURL,
1836 bool overwrite)
1838 // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
1839 KIO::Job *job = KIO::put(aURL, -1, overwrite ? KIO::Overwrite : KIO::DefaultFlags);
1840 putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
1841 mPutJobs.insert(job, pd);
1842 connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
1843 SLOT(slotDataReq(KIO::Job*,QByteArray&)));
1844 connect(job, SIGNAL(result(KJob*)),
1845 SLOT(slotResult(KJob*)));
1848 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
1850 // send the data in 64 KB chunks
1851 const int MAX_CHUNK_SIZE = 64*1024;
1852 QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
1853 assert(it != mPutJobs.end());
1854 int remainingBytes = (*it).data.size() - (*it).offset;
1855 if( remainingBytes > MAX_CHUNK_SIZE )
1857 // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
1858 data = QByteArray( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
1859 (*it).offset += MAX_CHUNK_SIZE;
1860 //kDebug( 5006 ) <<"Sending" << MAX_CHUNK_SIZE <<" bytes ("
1861 // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
1863 else
1865 // send the remaining bytes to the receiver (deep copy)
1866 data = QByteArray( (*it).data.data() + (*it).offset, remainingBytes );
1867 (*it).data = QByteArray();
1868 (*it).offset = 0;
1869 //kDebug( 5006 ) <<"Sending" << remainingBytes <<" bytes";
1873 void KMKernel::slotResult(KJob *job)
1875 QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(static_cast<KIO::Job*>(job));
1876 assert(it != mPutJobs.end());
1877 if (job->error())
1879 if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
1881 if (KMessageBox::warningContinueCancel(0,
1882 i18n("File %1 exists.\nDo you want to replace it?",
1883 (*it).url.prettyUrl()), i18n("Save to File"), KGuiItem(i18n("&Replace")))
1884 == KMessageBox::Continue)
1885 byteArrayToRemoteFile((*it).data, (*it).url, true);
1887 else {
1888 KIO::JobUiDelegate *ui = static_cast<KIO::Job*>( job )->ui();
1889 ui->showErrorMessage();
1892 mPutJobs.erase(it);
1895 void KMKernel::slotRequestConfigSync() {
1896 // ### FIXME: delay as promised in the kdoc of this function ;-)
1897 KMKernel::config()->sync();
1900 void KMKernel::slotShowConfigurationDialog()
1902 if( !mConfigureDialog ) {
1903 mConfigureDialog = new ConfigureDialog( 0, false );
1904 mConfigureDialog->setObjectName( "configure" );
1905 connect( mConfigureDialog, SIGNAL( configCommitted() ),
1906 this, SLOT( slotConfigChanged() ) );
1909 if( KMKernel::getKMMainWidget() == 0 ) {
1910 // ensure that there is a main widget available
1911 // as parts of the configure dialog (identity) rely on this
1912 // and this slot can be called when there is only a KMComposeWin showing
1913 KMMainWin *win = new KMMainWin;
1914 win->show();
1918 if( mConfigureDialog->isHidden() ) {
1919 mConfigureDialog->show();
1920 } else {
1921 mConfigureDialog->raise();
1925 void KMKernel::slotConfigChanged()
1927 readConfig();
1928 emit configChanged();
1931 //-------------------------------------------------------------------------------
1932 //static
1933 QString KMKernel::localDataPath()
1935 return KStandardDirs::locateLocal( "data", "kmail/" );
1938 //-------------------------------------------------------------------------------
1940 bool KMKernel::haveSystemTrayApplet()
1942 return !systemTrayApplets.isEmpty();
1945 bool KMKernel::registerSystemTrayApplet( const KSystemTrayIcon* applet )
1947 if ( !systemTrayApplets.contains( applet ) ) {
1948 systemTrayApplets.append( applet );
1949 return true;
1951 else
1952 return false;
1955 bool KMKernel::unregisterSystemTrayApplet( const KSystemTrayIcon* applet )
1957 return systemTrayApplets.removeAll( applet ) > 0;
1960 void KMKernel::emergencyExit( const QString& reason )
1962 QString mesg;
1963 if ( reason.length() == 0 ) {
1964 mesg = i18n("KMail encountered a fatal error and will terminate now");
1966 else {
1967 mesg = i18n("KMail encountered a fatal error and will "
1968 "terminate now.\nThe error was:\n%1", reason );
1971 kWarning(5006) << mesg;
1972 KMessageBox::error( 0, mesg );
1974 ::exit(1);
1978 * Returns true if the folder is either the outbox or one of the drafts-folders
1980 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
1982 assert( folder );
1983 if ( folder == the_outboxFolder )
1984 return true;
1985 return folderIsDrafts( folder );
1988 bool KMKernel::folderIsDrafts(const KMFolder * folder)
1990 assert( folder );
1991 if ( folder == the_draftsFolder )
1992 return true;
1994 QString idString = folder->idString();
1995 if ( idString.isEmpty() ) return false;
1997 // search the identities if the folder matches the drafts-folder
1998 const KPIMIdentities::IdentityManager * im = identityManager();
1999 for( KPIMIdentities::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
2000 if ( (*it).drafts() == idString ) return true;
2001 return false;
2004 bool KMKernel::folderIsTemplates(const KMFolder * folder)
2006 assert( folder );
2007 if ( folder == the_templatesFolder )
2008 return true;
2010 QString idString = folder->idString();
2011 if ( idString.isEmpty() ) return false;
2013 // search the identities if the folder matches the templates-folder
2014 const KPIMIdentities::IdentityManager * im = identityManager();
2015 for( KPIMIdentities::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
2016 if ( (*it).templates() == idString ) return true;
2017 return false;
2020 bool KMKernel::folderIsTrash(KMFolder * folder)
2022 assert(folder);
2023 if (folder == the_trashFolder) return true;
2024 QStringList actList = acctMgr()->getAccounts();
2025 QStringList::Iterator it( actList.begin() );
2026 for( ; it != actList.end() ; ++it ) {
2027 KMAccount* act = acctMgr()->findByName( *it );
2028 if ( act && ( act->trash() == folder->idString() ) )
2029 return true;
2031 return false;
2034 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
2036 assert( folder );
2037 if ( folder == the_sentFolder )
2038 return true;
2040 QString idString = folder->idString();
2041 if ( idString.isEmpty() ) return false;
2043 // search the identities if the folder matches the sent-folder
2044 const KPIMIdentities::IdentityManager * im = identityManager();
2045 for( KPIMIdentities::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
2046 if ( (*it).fcc() == idString ) return true;
2047 return false;
2050 KPIMIdentities::IdentityManager * KMKernel::identityManager() {
2051 if ( !mIdentityManager ) {
2052 kDebug(5006);
2053 mIdentityManager = new KPIMIdentities::IdentityManager( false, this, "mIdentityManager" );
2055 return mIdentityManager;
2058 KMainWindow* KMKernel::mainWin()
2060 KMainWindow *kmWin = 0;
2062 // First look for a KMMainWin.
2063 foreach ( KMainWindow* window, KMainWindow::memberList() )
2064 if ( ::qobject_cast<KMMainWin *>(window) )
2065 return kmWin;
2067 // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
2068 // case we are running inside Kontact) because we anyway only need
2069 // it for modal message boxes and for KNotify events.
2070 kmWin = KMainWindow::memberList().first();
2071 if ( kmWin )
2072 return kmWin;
2074 // There's not a single KMainWindow. Create a KMMainWin.
2075 // This could happen if we want to pop up an error message
2076 // while we are still doing the startup wizard and no other
2077 // KMainWindow is running.
2078 mWin = new KMMainWin;
2079 return mWin;
2084 * Empties all trash folders
2086 void KMKernel::slotEmptyTrash()
2088 QString title = i18n("Empty Trash");
2089 QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
2090 if (KMessageBox::warningContinueCancel(0, text, title,
2091 KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
2092 "confirm_empty_trash")
2093 != KMessageBox::Continue)
2095 return;
2098 QList<KMAccount*>::iterator accountIt = acctMgr()->begin();
2099 while ( accountIt != acctMgr()->end() ) {
2100 KMAccount *acct = *accountIt;
2101 ++accountIt;
2102 KMFolder* trash = findFolderById(acct->trash());
2103 if (trash)
2105 trash->expunge();
2110 KMKernel* KMKernel::self()
2112 assert( mySelf );
2113 return mySelf;
2116 KConfig* KMKernel::config()
2118 assert( mySelf );
2119 if ( !mySelf->mConfig )
2121 mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
2122 // Check that all updates have been run on the config file:
2123 KMail::checkConfigUpdates();
2125 return mySelf->mConfig.data();
2128 KMailICalIfaceImpl& KMKernel::iCalIface()
2130 assert( mICalIface );
2131 return *mICalIface;
2134 void KMKernel::selectFolder( const QString &folderPath )
2136 kDebug(5006)<<"Selecting a folder"<<folderPath;
2137 const QString localPrefix = "/Local";
2138 KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
2139 if ( !folder && folderPath.startsWith( localPrefix ) )
2140 folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
2141 if ( !folder )
2142 folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
2143 if ( !folder )
2144 folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
2145 Q_ASSERT( folder );
2147 KMMainWidget *widget = getKMMainWidget();
2148 Q_ASSERT( widget );
2149 if ( !widget )
2150 return;
2152 widget->mainFolderView()->setCurrentFolder( folder );
2155 KMMainWidget *KMKernel::getKMMainWidget()
2157 //This could definitely use a speadup
2158 QWidgetList l = QApplication::topLevelWidgets();
2159 QWidget *wid;
2161 Q_FOREACH( wid, l ) {
2162 QList<KMMainWidget*> l2 = wid->topLevelWidget()->findChildren<KMMainWidget*>();
2163 if ( !l2.isEmpty() && l2.first() )
2164 return l2.first();
2166 return 0;
2169 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
2171 // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
2172 // a stable kmail release goes out with a nasty bug in CompactionJob...
2173 KConfigGroup generalGroup( config(), "General" );
2175 if ( generalGroup.readEntry( "auto-expiring", true ) ) {
2176 if ( the_folderMgr )
2177 the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2178 if ( the_imapFolderMgr )
2179 the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2180 if ( the_dimapFolderMgr )
2181 the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
2182 // the_searchFolderMgr: no expiry there
2185 if ( generalGroup.readEntry( "auto-compaction", true ) ) {
2186 if ( the_folderMgr )
2187 the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
2188 // the_imapFolderMgr: no compaction
2189 if ( the_dimapFolderMgr )
2190 the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
2191 // the_searchFolderMgr: no compaction
2194 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
2195 mBackgroundTasksTimer->start( 60 * 1000 ); // check again in 1 minute
2196 #else
2197 mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000 ); // check again in 4 hours
2198 #endif
2202 void KMKernel::expireAllFoldersNow() // called by the GUI
2204 the_folderMgr->expireAllFolders( true /*immediate*/ );
2205 the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
2206 the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
2209 void KMKernel::compactAllFolders() // called by the GUI
2211 the_folderMgr->compactAllFolders( true /*immediate*/ );
2212 //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
2213 the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
2216 KMFolder* KMKernel::findFolderById( const QString& idString )
2218 KMFolder * folder = the_folderMgr->findIdString( idString );
2219 if ( !folder )
2220 folder = the_imapFolderMgr->findIdString( idString );
2221 if ( !folder )
2222 folder = the_dimapFolderMgr->findIdString( idString );
2223 if ( !folder )
2224 folder = the_searchFolderMgr->findIdString( idString );
2225 return folder;
2228 void KMKernel::enableMailCheck()
2230 mMailCheckAborted = false;
2233 bool KMKernel::mailCheckAborted() const
2235 return mMailCheckAborted;
2238 void KMKernel::abortMailCheck()
2240 mMailCheckAborted = true;
2243 bool KMKernel::canQueryClose()
2245 if ( KMMainWidget::mainWidgetList() &&
2246 KMMainWidget::mainWidgetList()->count() > 1 )
2247 return true;
2248 KMMainWidget *widget = getKMMainWidget();
2249 if ( !widget )
2250 return true;
2251 KMSystemTray* systray = widget->systray();
2252 if ( !systray || GlobalSettings::closeDespiteSystemTray() )
2253 return true;
2254 if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
2255 systray->hideKMail();
2256 return false;
2257 } else if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
2258 systray->show();
2259 systray->hideKMail();
2260 return false;
2262 return true;
2265 void KMKernel::messageCountChanged()
2267 mTimeOfLastMessageCountChange = ::time( 0 );
2270 int KMKernel::timeOfLastMessageCountChange() const
2272 return mTimeOfLastMessageCountChange;
2275 Wallet *KMKernel::wallet() {
2276 static bool walletOpenFailed = false;
2277 if ( mWallet && mWallet->isOpen() )
2278 return mWallet;
2280 if ( !Wallet::isEnabled() || walletOpenFailed )
2281 return 0;
2283 // find an appropriate parent window for the wallet dialog
2284 WId window = 0;
2285 if ( qApp->activeWindow() )
2286 window = qApp->activeWindow()->winId();
2287 else if ( getKMMainWidget() )
2288 window = getKMMainWidget()->topLevelWidget()->winId();
2290 delete mWallet;
2291 mWallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
2293 if ( !mWallet ) {
2294 walletOpenFailed = true;
2295 return 0;
2298 if ( !mWallet->hasFolder( "kmail" ) )
2299 mWallet->createFolder( "kmail" );
2300 mWallet->setFolder( "kmail" );
2301 return mWallet;
2304 QList< QPointer<KMFolder> > KMKernel::allFolders()
2306 QStringList names;
2307 QList<QPointer<KMFolder> > folders;
2308 folderMgr()->createFolderList(&names, &folders);
2309 imapFolderMgr()->createFolderList(&names, &folders);
2310 dimapFolderMgr()->createFolderList(&names, &folders);
2311 searchFolderMgr()->createFolderList(&names, &folders);
2313 return folders;
2316 KMFolder *KMKernel::currentFolder() {
2317 KMMainWidget *widget = getKMMainWidget();
2318 KMFolder *folder = 0;
2319 if ( widget && widget->mainFolderView() ) {
2320 folder = widget->mainFolderView()->currentFolder();
2322 return folder;
2325 // can't be inline, since KMSender isn't known to implement
2326 // KMail::MessageSender outside this .cpp file
2327 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; }
2329 void KMKernel::transportRemoved(int id, const QString & name)
2331 Q_UNUSED( id );
2333 // reset all identities using the deleted transport
2334 QStringList changedIdents;
2335 KPIMIdentities::IdentityManager * im = identityManager();
2336 for ( KPIMIdentities::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
2337 if ( name == (*it).transport() ) {
2338 (*it).setTransport( QString() );
2339 changedIdents += (*it).identityName();
2343 // if the deleted transport is the currently used transport reset it to default
2344 const QString& currentTransport = GlobalSettings::self()->currentTransport();
2345 if ( name == currentTransport )
2346 GlobalSettings::self()->setCurrentTransport( QString() );
2348 if ( !changedIdents.isEmpty() ) {
2349 QString information = i18np( "This identity has been changed to use the default transport:",
2350 "These %1 identities have been changed to use the default transport:",
2351 changedIdents.count() );
2352 KMessageBox::informationList( mWin, information, changedIdents );
2353 im->commit();
2357 void KMKernel::transportRenamed(int id, const QString & oldName, const QString & newName)
2359 Q_UNUSED( id );
2361 QStringList changedIdents;
2362 KPIMIdentities::IdentityManager * im = identityManager();
2363 for ( KPIMIdentities::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
2364 if ( oldName == (*it).transport() ) {
2365 (*it).setTransport( newName );
2366 changedIdents << (*it).identityName();
2370 if ( !changedIdents.isEmpty() ) {
2371 QString information =
2372 i18np( "This identity has been changed to use the modified transport:",
2373 "These %1 identities have been changed to use the modified transport:",
2374 changedIdents.count() );
2375 KMessageBox::informationList( mWin, information, changedIdents );
2376 im->commit();
2380 void KMKernel::updatedTemplates()
2382 emit customTemplatesChanged();
2386 #include "kmkernel.moc"