kmail

kmkernel.cpp

00001 /*  -*- mode: C++; c-file-style: "gnu" -*- */
00002 #ifdef HAVE_CONFIG_H
00003 #include <config.h>
00004 #endif
00005 
00006 #include "config.h"
00007 #include "kmkernel.h"
00008 
00009 #include <weaver.h>
00010 #include <weaverlogger.h>
00011 
00012 #include "globalsettings.h"
00013 #include "broadcaststatus.h"
00014 using KPIM::BroadcastStatus;
00015 #include "kmstartup.h"
00016 #include "index.h"
00017 #include "kmmainwin.h"
00018 #include "composer.h"
00019 #include "kmmsgpart.h"
00020 #include "kmreadermainwin.h"
00021 #include "kmfoldermgr.h"
00022 #include "kmfoldercachedimap.h"
00023 #include "kmacctcachedimap.h"
00024 #include "kmfiltermgr.h"
00025 #include "kmfilteraction.h"
00026 #define REALLY_WANT_KMSENDER
00027 #include "kmsender.h"
00028 #undef REALLY_WANT_KMSENDER
00029 #include "undostack.h"
00030 #include "accountmanager.h"
00031 using KMail::AccountManager;
00032 #include <libkdepim/kfileio.h>
00033 #include "kmversion.h"
00034 #include "kmreaderwin.h"
00035 #include "kmmainwidget.h"
00036 #include "kmfoldertree.h"
00037 #include "recentaddresses.h"
00038 using KRecentAddress::RecentAddresses;
00039 #include "kmmsgdict.h"
00040 #include <libkpimidentities/identity.h>
00041 #include <libkpimidentities/identitymanager.h>
00042 #include "configuredialog.h"
00043 #include "kmcommands.h"
00044 #include "kmsystemtray.h"
00045 #include "transportmanager.h"
00046 
00047 #include <kwin.h>
00048 #include "kmailicalifaceimpl.h"
00049 #include "mailserviceimpl.h"
00050 using KMail::MailServiceImpl;
00051 #include "mailcomposerIface.h"
00052 #include "folderIface.h"
00053 using KMail::FolderIface;
00054 #include "jobscheduler.h"
00055 
00056 #include <kapplication.h>
00057 #include <kmessagebox.h>
00058 #include <knotifyclient.h>
00059 #include <kstaticdeleter.h>
00060 #include <kstandarddirs.h>
00061 #include <kconfig.h>
00062 #include <kprogress.h>
00063 #include <kpassivepopup.h>
00064 #include <dcopclient.h>
00065 #include <ksystemtray.h>
00066 #include <kpgp.h>
00067 #include <kdebug.h>
00068 #include <kio/netaccess.h>
00069 #include <kwallet.h>
00070 using KWallet::Wallet;
00071 #include "actionscheduler.h"
00072 
00073 #include <qutf7codec.h>
00074 #include <qvbox.h>
00075 #include <qdir.h>
00076 #include <qwidgetlist.h>
00077 #include <qobjectlist.h>
00078 
00079 #include <sys/types.h>
00080 #include <dirent.h>
00081 #include <sys/stat.h>
00082 #include <unistd.h>
00083 #include <stdio.h>
00084 #include <stdlib.h>
00085 #include <assert.h>
00086 
00087 #include <X11/Xlib.h>
00088 #include <fixx11h.h>
00089 #include <kcmdlineargs.h>
00090 #include <kstartupinfo.h>
00091 
00092 KMKernel *KMKernel::mySelf = 0;
00093 
00094 /********************************************************************/
00095 /*                     Constructor and destructor                   */
00096 /********************************************************************/
00097 KMKernel::KMKernel (QObject *parent, const char *name) :
00098   DCOPObject("KMailIface"), QObject(parent, name),
00099   mIdentityManager(0), mConfigureDialog(0),
00100   mContextMenuShown( false ), mWallet( 0 )
00101 {
00102   kdDebug(5006) << "KMKernel::KMKernel" << endl;
00103   mySelf = this;
00104   the_startingUp = true;
00105   closed_by_user = true;
00106   the_firstInstance = true;
00107   the_msgIndex = 0;
00108 
00109   the_inboxFolder = 0;
00110   the_outboxFolder = 0;
00111   the_sentFolder = 0;
00112   the_trashFolder = 0;
00113   the_draftsFolder = 0;
00114 
00115   the_folderMgr = 0;
00116   the_imapFolderMgr = 0;
00117   the_dimapFolderMgr = 0;
00118   the_searchFolderMgr = 0;
00119   the_undoStack = 0;
00120   the_acctMgr = 0;
00121   the_filterMgr = 0;
00122   the_popFilterMgr = 0;
00123   the_filterActionDict = 0;
00124   the_msgSender = 0;
00125   mWin = 0;
00126   mMailCheckAborted = false;
00127 
00128   // make sure that we check for config updates before doing anything else
00129   KMKernel::config();
00130   // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it
00131   // so better do it here, than in some code where changing the group of config()
00132   // would be unexpected
00133   GlobalSettings::self();
00134 
00135   // Set up DCOP interface
00136   mICalIface = new KMailICalIfaceImpl();
00137 
00138   mJobScheduler = new JobScheduler( this );
00139 
00140   mXmlGuiInstance = 0;
00141 
00142   new Kpgp::Module();
00143 
00144   // register our own (libkdenetwork) utf-7 codec as long as Qt
00145   // doesn't have it's own:
00146   if ( !QTextCodec::codecForName("utf-7") ) {
00147     kdDebug(5006) << "No Qt-native utf-7 codec found; registering QUtf7Codec from libkdenetwork" << endl;
00148     (void) new QUtf7Codec();
00149   }
00150 
00151   // In the case of Japan. Japanese locale name is "eucjp" but
00152   // The Japanese mail systems normally used "iso-2022-jp" of locale name.
00153   // We want to change locale name from eucjp to iso-2022-jp at KMail only.
00154   if ( QCString(QTextCodec::codecForLocale()->name()).lower() == "eucjp" )
00155   {
00156     netCodec = QTextCodec::codecForName("jis7");
00157     // QTextCodec *cdc = QTextCodec::codecForName("jis7");
00158     // QTextCodec::setCodecForLocale(cdc);
00159     // KGlobal::locale()->setEncoding(cdc->mibEnum());
00160   } else {
00161     netCodec = QTextCodec::codecForLocale();
00162   }
00163   mMailService =  new MailServiceImpl();
00164 
00165   connectDCOPSignal( 0, 0, "kmailSelectFolder(QString)",
00166                      "selectFolder(QString)", false );
00167 }
00168 
00169 KMKernel::~KMKernel ()
00170 {
00171   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.begin();
00172   while ( it != mPutJobs.end() )
00173   {
00174     KIO::Job *job = it.key();
00175     mPutJobs.remove( it );
00176     job->kill();
00177     it = mPutJobs.begin();
00178   }
00179 
00180   delete mICalIface;
00181   mICalIface = 0;
00182   delete mMailService;
00183   mMailService = 0;
00184 
00185   GlobalSettings::self()->writeConfig();
00186   delete mWallet;
00187   mWallet = 0;
00188   mySelf = 0;
00189   kdDebug(5006) << "KMKernel::~KMKernel" << endl;
00190 }
00191 
00192 bool KMKernel::handleCommandLine( bool noArgsOpensReader )
00193 {
00194   QString to, cc, bcc, subj, body;
00195   KURL messageFile;
00196   KURL::List attachURLs;
00197   bool mailto = false;
00198   bool checkMail = false;
00199   bool viewOnly = false;
00200   bool calledWithSession = false; // for ignoring '-session foo'
00201 
00202   // process args:
00203   KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00204   if (args->getOption("subject"))
00205   {
00206      subj = QString::fromLocal8Bit(args->getOption("subject"));
00207      // if kmail is called with 'kmail -session abc' then this doesn't mean
00208      // that the user wants to send a message with subject "ession" but
00209      // (most likely) that the user clicked on KMail's system tray applet
00210      // which results in KMKernel::raise() calling "kmail kmail newInstance"
00211      // via dcop which apparently executes the application with the original
00212      // command line arguments and those include "-session ..." if
00213      // kmail/kontact was restored by session management
00214      if ( subj == "ession" ) {
00215        subj = QString::null;
00216        calledWithSession = true;
00217      }
00218      else
00219        mailto = true;
00220   }
00221 
00222   if (args->getOption("cc"))
00223   {
00224      mailto = true;
00225      cc = QString::fromLocal8Bit(args->getOption("cc"));
00226   }
00227 
00228   if (args->getOption("bcc"))
00229   {
00230      mailto = true;
00231      bcc = QString::fromLocal8Bit(args->getOption("bcc"));
00232   }
00233 
00234   if (args->getOption("msg"))
00235   {
00236      mailto = true;
00237      messageFile.setPath( QString::fromLocal8Bit(args->getOption("msg")) );
00238   }
00239 
00240   if (args->getOption("body"))
00241   {
00242      mailto = true;
00243      body = QString::fromLocal8Bit(args->getOption("body"));
00244   }
00245 
00246   QCStringList attachList = args->getOptionList("attach");
00247   if (!attachList.isEmpty())
00248   {
00249      mailto = true;
00250      for ( QCStringList::Iterator it = attachList.begin() ; it != attachList.end() ; ++it )
00251        if ( !(*it).isEmpty() )
00252          attachURLs += KURL( QString::fromLocal8Bit( *it ) );
00253   }
00254 
00255   if (args->isSet("composer"))
00256     mailto = true;
00257 
00258   if (args->isSet("check"))
00259     checkMail = true;
00260 
00261   if ( args->getOption( "view" ) ) {
00262     viewOnly = true;
00263     const QString filename =
00264       QString::fromLocal8Bit( args->getOption( "view" ) );
00265     messageFile = KURL::fromPathOrURL( filename );
00266     if ( !messageFile.isValid() ) {
00267       messageFile = KURL();
00268       messageFile.setPath( filename );
00269     }
00270   }
00271 
00272   if ( !calledWithSession ) {
00273     // only read additional command line arguments if kmail/kontact is
00274     // not called with "-session foo"
00275     for(int i= 0; i < args->count(); i++)
00276     {
00277       if (strncasecmp(args->arg(i),"mailto:",7)==0)
00278         to += args->url(i).path() + ", ";
00279       else {
00280         QString tmpArg = QString::fromLocal8Bit( args->arg(i) );
00281         KURL url( tmpArg );
00282         if ( url.isValid() )
00283           attachURLs += url;
00284         else
00285           to += tmpArg + ", ";
00286       }
00287       mailto = true;
00288     }
00289     if ( !to.isEmpty() ) {
00290       // cut off the superfluous trailing ", "
00291       to.truncate( to.length() - 2 );
00292     }
00293   }
00294 
00295   if ( !calledWithSession )
00296     args->clear();
00297 
00298   if ( !noArgsOpensReader && !mailto && !checkMail && !viewOnly )
00299     return false;
00300 
00301   if ( viewOnly )
00302     viewMessage( messageFile );
00303   else
00304     action( mailto, checkMail, to, cc, bcc, subj, body, messageFile,
00305             attachURLs );
00306   return true;
00307 }
00308 
00309 /********************************************************************/
00310 /*             DCOP-callable, and command line actions              */
00311 /********************************************************************/
00312 void KMKernel::checkMail () //might create a new reader but won't show!!
00313 {
00314   kmkernel->acctMgr()->checkMail(false);
00315 }
00316 
00317 QStringList KMKernel::accounts()
00318 {
00319   return kmkernel->acctMgr()->getAccounts();
00320 }
00321 
00322 void KMKernel::checkAccount (const QString &account) //might create a new reader but won't show!!
00323 {
00324   kdDebug(5006) << "KMKernel::checkMail called" << endl;
00325 
00326   KMAccount* acct = kmkernel->acctMgr()->findByName(account);
00327   if (acct)
00328     kmkernel->acctMgr()->singleCheckMail(acct, false);
00329 }
00330 
00331 void KMKernel::openReader( bool onlyCheck )
00332 {
00333   KMMainWin *mWin = 0;
00334   KMainWindow *ktmw = 0;
00335   kdDebug(5006) << "KMKernel::openReader called" << endl;
00336 
00337   if (KMainWindow::memberList)
00338     for (ktmw = KMainWindow::memberList->first(); ktmw;
00339          ktmw = KMainWindow::memberList->next())
00340       if (ktmw->isA("KMMainWin"))
00341         break;
00342 
00343   bool activate;
00344   if (ktmw) {
00345     mWin = (KMMainWin *) ktmw;
00346     activate = !onlyCheck; // existing window: only activate if not --check
00347     if ( activate )
00348        mWin->show();
00349   }
00350   else {
00351     mWin = new KMMainWin;
00352     mWin->show();
00353     activate = false; // new window: no explicit activation (#73591)
00354   }
00355 
00356   if ( activate ) {
00357     // Activate window - doing this instead of KWin::activateWindow(mWin->winId());
00358     // so that it also works when called from KMailApplication::newInstance()
00359 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00360     KStartupInfo::setNewStartupId( mWin, kapp->startupId() );
00361 #endif
00362   }
00363 }
00364 
00365 int KMKernel::openComposer (const QString &to, const QString &cc,
00366                             const QString &bcc, const QString &subject,
00367                             const QString &body, int hidden,
00368                             const KURL &messageFile,
00369                             const KURL::List &attachURLs)
00370 {
00371   kdDebug(5006) << "KMKernel::openComposer called" << endl;
00372   KMMessage *msg = new KMMessage;
00373   msg->initHeader();
00374   msg->setCharset("utf-8");
00375   // tentatively decode to, cc and bcc because invokeMailer calls us with
00376   // RFC 2047 encoded addresses in order to protect non-ASCII email addresses
00377   if (!to.isEmpty())
00378     msg->setTo( KMMsgBase::decodeRFC2047String( to.latin1() ) );
00379   if (!cc.isEmpty())
00380     msg->setCc( KMMsgBase::decodeRFC2047String( cc.latin1() ) );
00381   if (!bcc.isEmpty())
00382     msg->setBcc( KMMsgBase::decodeRFC2047String( bcc.latin1() ) );
00383   if (!subject.isEmpty()) msg->setSubject(subject);
00384   if (!messageFile.isEmpty() && messageFile.isLocalFile()) {
00385     QCString str = KPIM::kFileToString( messageFile.path(), true, false );
00386     if( !str.isEmpty() )
00387       msg->setBody( QString::fromLocal8Bit( str ).utf8() );
00388   }
00389   else if (!body.isEmpty())
00390     msg->setBody(body.utf8());
00391 
00392   KMail::Composer * cWin = KMail::makeComposer( msg );
00393   cWin->setCharset("", TRUE);
00394   for ( KURL::List::ConstIterator it = attachURLs.begin() ; it != attachURLs.end() ; ++it )
00395     cWin->addAttach((*it));
00396   if (hidden == 0) {
00397     cWin->show();
00398     // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
00399     // so that it also works when called from KMailApplication::newInstance()
00400 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00401     KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
00402 #endif
00403   }
00404   return 1;
00405 }
00406 
00407 
00408 int KMKernel::openComposer (const QString &to, const QString &cc,
00409                             const QString &bcc, const QString &subject,
00410                             const QString &body, int hidden,
00411                             const QString &attachName,
00412                             const QCString &attachCte,
00413                             const QCString &attachData,
00414                             const QCString &attachType,
00415                             const QCString &attachSubType,
00416                             const QCString &attachParamAttr,
00417                             const QString &attachParamValue,
00418                             const QCString &attachContDisp )
00419 {
00420   kdDebug(5006) << "KMKernel::openComposer called (deprecated version)" << endl;
00421 
00422   return openComposer ( to, cc, bcc, subject, body, hidden,
00423                         attachName, attachCte, attachData,
00424                         attachType, attachSubType, attachParamAttr,
00425                         attachParamValue, attachContDisp, QCString() );
00426 }
00427 
00428 int KMKernel::openComposer (const QString &to, const QString &cc,
00429                             const QString &bcc, const QString &subject,
00430                             const QString &body, int hidden,
00431                             const QString &attachName,
00432                             const QCString &attachCte,
00433                             const QCString &attachData,
00434                             const QCString &attachType,
00435                             const QCString &attachSubType,
00436                             const QCString &attachParamAttr,
00437                             const QString &attachParamValue,
00438                             const QCString &attachContDisp,
00439                             const QCString &attachCharset )
00440 {
00441   kdDebug(5006) << "KMKernel::openComposer()" << endl;
00442 
00443   KMMessage *msg = new KMMessage;
00444   KMMessagePart *msgPart = 0;
00445   msg->initHeader();
00446   msg->setCharset( "utf-8" );
00447   if ( !cc.isEmpty() ) msg->setCc(cc);
00448   if ( !bcc.isEmpty() ) msg->setBcc(bcc);
00449   if ( !subject.isEmpty() ) msg->setSubject(subject);
00450   if ( !to.isEmpty() ) msg->setTo(to);
00451   if ( !body.isEmpty() ) msg->setBody(body.utf8());
00452 
00453   bool iCalAutoSend = false;
00454   bool noWordWrap = false;
00455   bool isICalInvitation = false;
00456   KConfigGroup options( config(), "Groupware" );
00457   if ( !attachData.isEmpty() ) {
00458     isICalInvitation = attachName == "cal.ics" &&
00459       attachType == "text" &&
00460       attachSubType == "calendar" &&
00461       attachParamAttr == "method";
00462     // Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
00463     if ( isICalInvitation && bcc.isEmpty() )
00464       msg->setBcc( "" );
00465     if ( isICalInvitation &&
00466         GlobalSettings::self()->legacyBodyInvites() ) {
00467       // KOrganizer invitation caught and to be sent as body instead
00468       msg->setBody( attachData );
00469       msg->setHeaderField( "Content-Type",
00470                            QString( "text/calendar; method=%1; "
00471                                     "charset=\"utf-8\"" ).
00472                            arg( attachParamValue ) );
00473 
00474       iCalAutoSend = true; // no point in editing raw ICAL
00475       noWordWrap = true; // we shant word wrap inline invitations
00476     } else {
00477       // Just do what we're told to do
00478       msgPart = new KMMessagePart;
00479       msgPart->setName( attachName );
00480       msgPart->setCteStr( attachCte );
00481       msgPart->setBodyEncoded( attachData );
00482       msgPart->setTypeStr( attachType );
00483       msgPart->setSubtypeStr( attachSubType );
00484       msgPart->setParameter( attachParamAttr, attachParamValue );
00485       msgPart->setContentDisposition( attachContDisp );
00486       if( !attachCharset.isEmpty() ) {
00487         // kdDebug(5006) << "KMKernel::openComposer set attachCharset to "
00488         // << attachCharset << endl;
00489         msgPart->setCharset( attachCharset );
00490       }
00491       // Don't show the composer window, if the automatic sending is checked
00492       KConfigGroup options(  config(), "Groupware" );
00493       iCalAutoSend = options.readBoolEntry( "AutomaticSending", true );
00494     }
00495   }
00496 
00497   KMail::Composer * cWin = KMail::makeComposer();
00498   cWin->setMsg( msg, !isICalInvitation /* mayAutoSign */ );
00499   cWin->setSigningAndEncryptionDisabled( isICalInvitation
00500       && GlobalSettings::self()->legacyBodyInvites() );
00501   cWin->setAutoDelete( true );
00502   if( noWordWrap )
00503     cWin->slotWordWrapToggled( false );
00504   else
00505     cWin->setCharset( "", true );
00506   if ( msgPart )
00507     cWin->addAttach(msgPart);
00508 
00509   if ( hidden == 0 && !iCalAutoSend ) {
00510     cWin->show();
00511     // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
00512     // so that it also works when called from KMailApplication::newInstance()
00513 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00514     KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
00515 #endif
00516   } else {
00517     cWin->setAutoDeleteWindow( true );
00518     cWin->slotSendNow();
00519   }
00520 
00521   return 1;
00522 }
00523 
00524 void KMKernel::setDefaultTransport( const QString & transport )
00525 {
00526   QStringList availTransports = KMail::TransportManager::transportNames();
00527   QStringList::const_iterator it = availTransports.find( transport );
00528   if ( it == availTransports.end() ) {
00529     kdWarning() << "The transport you entered is not available" << endl;
00530     return;
00531   }
00532   GlobalSettings::self()->setDefaultTransport( transport );
00533 }
00534 
00535 DCOPRef KMKernel::openComposer(const QString &to, const QString &cc,
00536                                const QString &bcc, const QString &subject,
00537                                const QString &body,bool hidden)
00538 {
00539   KMMessage *msg = new KMMessage;
00540   msg->initHeader();
00541   msg->setCharset("utf-8");
00542   if (!cc.isEmpty()) msg->setCc(cc);
00543   if (!bcc.isEmpty()) msg->setBcc(bcc);
00544   if (!subject.isEmpty()) msg->setSubject(subject);
00545   if (!to.isEmpty()) msg->setTo(to);
00546   if (!body.isEmpty()) msg->setBody(body.utf8());
00547 
00548   KMail::Composer * cWin = KMail::makeComposer( msg );
00549   cWin->setCharset("", TRUE);
00550   if (!hidden) {
00551     cWin->show();
00552     // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
00553     // so that it also works when called from KMailApplication::newInstance()
00554 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00555     KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
00556 #endif
00557   }
00558 
00559   return DCOPRef( cWin->asMailComposerIFace() );
00560 }
00561 
00562 DCOPRef KMKernel::newMessage(const QString &to,
00563                              const QString &cc,
00564                              const QString &bcc,
00565                              bool hidden,
00566                              bool useFolderId,
00567                              const KURL & /*messageFile*/,
00568                              const KURL &attachURL)
00569 {
00570   KMail::Composer * win = 0;
00571   KMMessage *msg = new KMMessage;
00572 
00573   if ( useFolderId ) {
00574     //create message with required folder identity
00575     KMFolder *folder = currentFolder();
00576     uint id = folder ? folder->identity() : 0;
00577     msg->initHeader( id );
00578     win = makeComposer( msg, id );
00579   } else {
00580     msg->initHeader();
00581     win = makeComposer( msg );
00582   }
00583   msg->setCharset("utf-8");
00584   //set basic headers
00585   if (!to.isEmpty()) msg->setTo(to);
00586   if (!cc.isEmpty()) msg->setCc(cc);
00587   if (!bcc.isEmpty()) msg->setBcc(bcc);
00588 
00589   //Add the attachment if we have one
00590   if(!attachURL.isEmpty() && attachURL.isValid()) {
00591     win->addAttach(attachURL);
00592   }
00593   //only show window when required
00594   if(!hidden) {
00595     win->show();
00596   }
00597   return DCOPRef( win->asMailComposerIFace() );
00598 }
00599 
00600 int KMKernel::viewMessage( const KURL & messageFile )
00601 {
00602   KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( 0, messageFile );
00603 
00604   openCommand->start();
00605 
00606   return 1;
00607 }
00608 
00609 int KMKernel::sendCertificate( const QString& to, const QByteArray& certData )
00610 {
00611   KMMessage *msg = new KMMessage;
00612   msg->initHeader();
00613   msg->setCharset("utf-8");
00614   msg->setSubject( i18n( "Certificate Signature Request" ) );
00615   if (!to.isEmpty()) msg->setTo(to);
00616   // ### Make this message customizable via KIOSK
00617   msg->setBody( i18n( "Please create a certificate from attachment and return to sender." ).utf8() );
00618 
00619   KMail::Composer * cWin = KMail::makeComposer( msg );
00620   cWin->setCharset("", TRUE);
00621   cWin->slotSetAlwaysSend( true );
00622   if (!certData.isEmpty()) {
00623     KMMessagePart *msgPart = new KMMessagePart;
00624     msgPart->setName("smime.p10");
00625     msgPart->setCteStr("base64");
00626     msgPart->setBodyEncodedBinary(certData);
00627     msgPart->setTypeStr("application");
00628     msgPart->setSubtypeStr("pkcs10");
00629     msgPart->setContentDisposition("attachment; filename=smime.p10");
00630     cWin->addAttach(msgPart);
00631   }
00632 
00633   cWin->show();
00634   return 1;
00635 }
00636 
00637 KMMsgStatus KMKernel::strToStatus(const QString &flags)
00638 {
00639     KMMsgStatus status = 0;
00640     if (!flags.isEmpty()) {
00641         for (uint n = 0; n < flags.length() ; n++) {
00642             switch (flags[n]) {
00643                 case 'N':
00644                     status |= KMMsgStatusNew;
00645                     break;
00646                 case 'U':
00647                     status |= KMMsgStatusUnread;
00648                     break;
00649                 case 'O':
00650                     status |= KMMsgStatusOld;
00651                     break;
00652                 case 'R':
00653                     status |= KMMsgStatusRead;
00654                     break;
00655                 case 'D':
00656                     status |= KMMsgStatusDeleted;
00657                     break;
00658                 case 'A':
00659                     status |= KMMsgStatusReplied;
00660                     break;
00661                 case 'F':
00662                     status |= KMMsgStatusForwarded;
00663                     break;
00664                 case 'Q':
00665                     status |= KMMsgStatusQueued;
00666                     break;
00667                 case 'K':
00668                     status |= KMMsgStatusTodo;
00669                     break;
00670                 case 'S':
00671                     status |= KMMsgStatusSent;
00672                     break;
00673                 case 'G':
00674                     status |= KMMsgStatusFlag;
00675                     break;
00676                 case 'W':
00677                     status |= KMMsgStatusWatched;
00678                     break;
00679                 case 'I':
00680                     status |= KMMsgStatusIgnored;
00681                     break;
00682                 case 'P':
00683                     status |= KMMsgStatusSpam;
00684                     break;
00685                 case 'H':
00686                     status |= KMMsgStatusHam;
00687                     break;
00688                 case 'T':
00689                     status |= KMMsgStatusHasAttach;
00690                     break;
00691                 case 'C':
00692                     status |= KMMsgStatusHasNoAttach;
00693                     break;
00694                 default:
00695                     break;
00696             }
00697         }
00698     }
00699     return status;
00700 }
00701 
00702 int KMKernel::dcopAddMessage( const QString & foldername, const QString & msgUrlString,
00703                               const QString & MsgStatusFlags)
00704 {
00705   return dcopAddMessage(foldername, KURL(msgUrlString), MsgStatusFlags);
00706 }
00707 
00708 int KMKernel::dcopAddMessage( const QString & foldername,const KURL & msgUrl,
00709                               const QString & MsgStatusFlags)
00710 {
00711   kdDebug(5006) << "KMKernel::dcopAddMessage called" << endl;
00712 
00713   if ( foldername.isEmpty() || foldername.startsWith("."))
00714     return -1;
00715 
00716   int retval;
00717   bool readFolderMsgIds = false;
00718   QString _foldername = foldername.stripWhiteSpace();
00719   _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences
00720 
00721   if ( foldername != mAddMessageLastFolder ) {
00722     mAddMessageMsgIds.clear();
00723     readFolderMsgIds = true;
00724     mAddMessageLastFolder = foldername;
00725   }
00726 
00727   if (!msgUrl.isEmpty() && msgUrl.isLocalFile()) {
00728 
00729     // This is a proposed change by Daniel Andor.
00730     // He proposed to change from the fopen(blah)
00731     // to a KPIM::kFileToString(blah).
00732     // Although it assigns a QString to a QString,
00733     // because of the implicit sharing this poses
00734     // no memory or performance penalty.
00735 
00736     const QCString messageText =
00737       KPIM::kFileToString( msgUrl.path(), true, false );
00738     if ( messageText.isEmpty() )
00739       return -2;
00740 
00741     KMMessage *msg = new KMMessage();
00742     msg->fromString( messageText );
00743 
00744     if (readFolderMsgIds) {
00745       if ( foldername.contains("/")) {
00746         QString tmp_fname = "";
00747         KMFolder *folder = NULL;
00748         KMFolderDir *subfolder;
00749         bool root = true;
00750 
00751         QStringList subFList = QStringList::split("/",_foldername,FALSE);
00752 
00753         for ( QStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
00754           QString _newFolder = *it;
00755           if(_newFolder.startsWith(".")) return -1;
00756 
00757           if(root) {
00758             folder = the_folderMgr->findOrCreate(*it, false);
00759             if (folder) {
00760               root = false;
00761               tmp_fname = "/" + *it;
00762             }
00763             else return -1;
00764           }
00765           else {
00766             subfolder = folder->createChildFolder();
00767             tmp_fname += "/" + *it;
00768             if(!the_folderMgr->getFolderByURL( tmp_fname )) {
00769              folder = the_folderMgr->createFolder(*it, FALSE, folder->folderType(), subfolder);
00770             }
00771 
00772             if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
00773           }
00774         }
00775 
00776         mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
00777         if(!folder) return -1;
00778 
00779       }
00780       else {
00781         mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
00782       }
00783     }
00784 
00785     if ( mAddMsgCurrentFolder ) {
00786       if (readFolderMsgIds) {
00787 
00788         // OLD COMMENT:
00789         // Try to determine if a message already exists in
00790         // the folder. The message id that is searched for, is
00791         // the subject line + the date. This should be quite
00792         // unique. The change that a given date with a given
00793         // subject is in the folder twice is very small.
00794         // If the subject is empty, the fromStrip string
00795         // is taken.
00796 
00797     // NEW COMMENT from Danny Kukawka (danny.kukawka@web.de):
00798     // subject line + the date is only unique if the following
00799     // return a correct unique value:
00800     //  time_t  DT = mb->date();
00801         //  QString dt = ctime(&DT);
00802     // But if the datestring in the Header isn't RFC conform
00803     // subject line + the date isn't unique.
00804     //
00805     // The only uique headerfield is the Message-ID. In some
00806     // cases this could be empty. I then I use the
00807     // subject line + dateStr .
00808 
00809         int i;
00810 
00811         mAddMsgCurrentFolder->open();
00812         for( i=0; i<mAddMsgCurrentFolder->count(); i++) {
00813           KMMsgBase *mb = mAddMsgCurrentFolder->getMsgBase(i);
00814       QString id = mb->msgIdMD5();
00815       if ( id.isEmpty() ) {
00816             id = mb->subject();
00817             if ( id.isEmpty() )
00818               id = mb->fromStrip();
00819             if ( id.isEmpty() )
00820               id = mb->toStrip();
00821 
00822             id += mb->dateStr();
00823       }
00824 
00825           //fprintf(stderr,"%s\n",(const char *) id);
00826           if ( !id.isEmpty() ) {
00827             mAddMessageMsgIds.append(id);
00828           }
00829         }
00830         mAddMsgCurrentFolder->close();
00831       }
00832 
00833       QString msgId = msg->msgIdMD5();
00834       if ( msgId.isEmpty()) {
00835     msgId = msg->subject();
00836     if ( msgId.isEmpty() )
00837           msgId = msg->fromStrip();
00838         if ( msgId.isEmpty() )
00839           msgId = msg->toStrip();
00840 
00841     msgId += msg->dateStr();
00842       }
00843 
00844       int k = mAddMessageMsgIds.findIndex( msgId );
00845       //fprintf(stderr,"find %s = %d\n",(const char *) msgId,k);
00846 
00847       if ( k == -1 ) {
00848         if ( !msgId.isEmpty() ) {
00849           mAddMessageMsgIds.append( msgId );
00850         }
00851 
00852         if ( !MsgStatusFlags.isEmpty() ) {
00853           KMMsgStatus status = strToStatus(MsgStatusFlags);
00854           if (status) msg->setStatus(status);
00855         }
00856 
00857         int index;
00858         if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
00859           mAddMsgCurrentFolder->unGetMsg( index );
00860           retval = 1;
00861         } else {
00862           retval =- 2;
00863           delete msg;
00864           msg = 0;
00865         }
00866       } else {
00867         //qDebug( "duplicate: " + msgId + "; subj: " + msg->subject() + ", from: " + msgId = msg->fromStrip());
00868     retval = -4;
00869       }
00870     } else {
00871       retval = -1;
00872     }
00873   } else {
00874     retval = -2;
00875   }
00876   return retval;
00877 }
00878 
00879 void KMKernel::dcopResetAddMessage()
00880 {
00881   mAddMessageMsgIds.clear();
00882   mAddMessageLastFolder = QString();
00883 }
00884 
00885 int KMKernel::dcopAddMessage_fastImport( const QString & foldername,
00886                                          const QString & msgUrlString,
00887                                          const QString & MsgStatusFlags)
00888 {
00889   return dcopAddMessage_fastImport(foldername, KURL(msgUrlString), MsgStatusFlags);
00890 }
00891 
00892 int KMKernel::dcopAddMessage_fastImport( const QString & foldername,
00893                                          const KURL & msgUrl,
00894                                          const QString & MsgStatusFlags)
00895 {
00896   // Use this function to import messages without
00897   // search for already existing emails.
00898   kdDebug(5006) << "KMKernel::dcopAddMessage_fastImport called" << endl;
00899 
00900   if ( foldername.isEmpty() || foldername.startsWith("."))
00901     return -1;
00902 
00903   int retval;
00904   bool createNewFolder = false;
00905 
00906   QString _foldername = foldername.stripWhiteSpace();
00907   _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences
00908 
00909   if ( foldername != mAddMessageLastFolder ) {
00910     createNewFolder = true;
00911     mAddMessageLastFolder = foldername;
00912   }
00913 
00914 
00915   if ( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) {
00916     const QCString messageText =
00917       KPIM::kFileToString( msgUrl.path(), true, false );
00918     if ( messageText.isEmpty() )
00919       return -2;
00920 
00921     KMMessage *msg = new KMMessage();
00922     msg->fromString( messageText );
00923 
00924     if (createNewFolder) {
00925       if ( foldername.contains("/")) {
00926         QString tmp_fname = "";
00927         KMFolder *folder = NULL;
00928         KMFolderDir *subfolder;
00929         bool root = true;
00930 
00931         QStringList subFList = QStringList::split("/",_foldername,FALSE);
00932 
00933         for ( QStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) {
00934           QString _newFolder = *it;
00935           if(_newFolder.startsWith(".")) return -1;
00936 
00937           if(root) {
00938             folder = the_folderMgr->findOrCreate(*it, false);
00939             if (folder) {
00940               root = false;
00941               tmp_fname = "/" + *it;
00942             }
00943             else return -1;
00944           }
00945           else {
00946             subfolder = folder->createChildFolder();
00947             tmp_fname += "/" + *it;
00948             if(!the_folderMgr->getFolderByURL( tmp_fname )) {
00949               folder = the_folderMgr->createFolder(*it, FALSE, folder->folderType(), subfolder);
00950             }
00951             if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1;
00952           }
00953         }
00954 
00955       mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname );
00956       if(!folder) return -1;
00957 
00958       }
00959       else {
00960         mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false);
00961       }
00962     }
00963 
00964     if ( mAddMsgCurrentFolder ) {
00965       int index;
00966 
00967       if( !MsgStatusFlags.isEmpty() ) {
00968         KMMsgStatus status = strToStatus(MsgStatusFlags);
00969         if (status) msg->setStatus(status);
00970       }
00971 
00972       if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) {
00973         mAddMsgCurrentFolder->unGetMsg( index );
00974         retval = 1;
00975       } else {
00976         retval =- 2;
00977         delete msg;
00978         msg = 0;
00979       }
00980     } else {
00981       retval = -1;
00982     }
00983   } else {
00984     retval = -2;
00985   }
00986 
00987   return retval;
00988 }
00989 
00990 QStringList KMKernel::folderList() const
00991 {
00992   QStringList folders;
00993   const QString localPrefix = "/Local";
00994   folders << localPrefix;
00995   the_folderMgr->getFolderURLS( folders, localPrefix );
00996   the_imapFolderMgr->getFolderURLS( folders );
00997   the_dimapFolderMgr->getFolderURLS( folders );
00998   return folders;
00999 }
01000 
01001 DCOPRef KMKernel::getFolder( const QString& vpath )
01002 {
01003   const QString localPrefix = "/Local";
01004   if ( the_folderMgr->getFolderByURL( vpath ) )
01005     return DCOPRef( new FolderIface( vpath ) );
01006   else if ( vpath.startsWith( localPrefix ) &&
01007             the_folderMgr->getFolderByURL( vpath.mid( localPrefix.length() ) ) )
01008     return DCOPRef( new FolderIface( vpath.mid( localPrefix.length() ) ) );
01009   else if ( the_imapFolderMgr->getFolderByURL( vpath ) )
01010     return DCOPRef( new FolderIface( vpath ) );
01011   else if ( the_dimapFolderMgr->getFolderByURL( vpath ) )
01012     return DCOPRef( new FolderIface( vpath ) );
01013   return DCOPRef();
01014 }
01015 
01016 void KMKernel::raise()
01017 {
01018   DCOPRef kmail( "kmail", "kmail" );
01019   kmail.call( "newInstance" );
01020 }
01021 
01022 bool KMKernel::showMail( Q_UINT32 serialNumber, QString /* messageId */ )
01023 {
01024   KMMainWidget *mainWidget = 0;
01025   if (KMainWindow::memberList) {
01026     KMainWindow *win = 0;
01027     QObjectList *l;
01028 
01029     // First look for a KMainWindow.
01030     for (win = KMainWindow::memberList->first(); win;
01031          win = KMainWindow::memberList->next()) {
01032       // Then look for a KMMainWidget.
01033       l = win->queryList("KMMainWidget");
01034       if (l && l->first()) {
01035     mainWidget = dynamic_cast<KMMainWidget *>(l->first());
01036     if (win->isActiveWindow())
01037       break;
01038       }
01039     }
01040   }
01041 
01042   if (mainWidget) {
01043     int idx = -1;
01044     KMFolder *folder = 0;
01045     KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
01046     if (!folder || (idx == -1))
01047       return false;
01048     folder->open();
01049     KMMsgBase *msgBase = folder->getMsgBase(idx);
01050     if (!msgBase)
01051       return false;
01052     bool unGet = !msgBase->isMessage();
01053     KMMessage *msg = folder->getMsg(idx);
01054 
01055     KMReaderMainWin *win = new KMReaderMainWin( false, false );
01056     KMMessage *newMessage = new KMMessage( *msg );
01057     newMessage->setParent( msg->parent() );
01058     newMessage->setMsgSerNum( msg->getMsgSerNum() );
01059     newMessage->setReadyToShow( true );
01060     win->showMsg( GlobalSettings::self()->overrideCharacterEncoding(), newMessage );
01061     win->show();
01062 
01063     if (unGet)
01064       folder->unGetMsg(idx);
01065     folder->close();
01066     return true;
01067   }
01068 
01069   return false;
01070 }
01071 
01072 QString KMKernel::getFrom( Q_UINT32 serialNumber )
01073 {
01074   int idx = -1;
01075   KMFolder *folder = 0;
01076   KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx);
01077   if (!folder || (idx == -1))
01078     return QString::null;
01079   folder->open();
01080   KMMsgBase *msgBase = folder->getMsgBase(idx);
01081   if (!msgBase)
01082     return QString::null;
01083   bool unGet = !msgBase->isMessage();
01084   KMMessage *msg = folder->getMsg(idx);
01085   QString result = msg->from();
01086   if (unGet)
01087     folder->unGetMsg(idx);
01088   folder->close();
01089   return result;
01090 }
01091 
01092 QString KMKernel::debugScheduler()
01093 {
01094   QString res = KMail::ActionScheduler::debug();
01095   return res;
01096 }
01097 
01098 QString KMKernel::debugSernum( Q_UINT32 serialNumber )
01099 {
01100   QString res;
01101   if (serialNumber != 0) {
01102     int idx = -1;
01103     KMFolder *folder = 0;
01104     KMMsgBase *msg = 0;
01105     KMMsgDict::instance()->getLocation( serialNumber, &folder, &idx );
01106     // It's possible that the message has been deleted or moved into a
01107     // different folder
01108     if (folder && (idx != -1)) {
01109       // everything is ok
01110       folder->open();
01111       msg = folder->getMsgBase( idx );
01112       if (msg) {
01113     res.append( QString( " subject %s,\n sender %s,\n date %s.\n" )
01114             .arg( msg->subject() )
01115             .arg( msg->fromStrip() )
01116             .arg( msg->dateStr() ) );
01117       } else {
01118     res.append( QString( "Invalid serial number." ) );
01119       }
01120       folder->close();
01121     } else {
01122       res.append( QString( "Invalid serial number." ) );
01123     }
01124   }
01125   return res;
01126 }
01127 
01128 
01129 void KMKernel::pauseBackgroundJobs()
01130 {
01131   mBackgroundTasksTimer->stop();
01132   mJobScheduler->pause();
01133 }
01134 
01135 void KMKernel::resumeBackgroundJobs()
01136 {
01137   mJobScheduler->resume();
01138   mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true );
01139 }
01140 
01141 void KMKernel::stopNetworkJobs()
01142 {
01143   if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
01144     return;
01145 
01146   GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Offline );
01147   BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended"));
01148   emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
01149 }
01150 
01151 void KMKernel::resumeNetworkJobs()
01152 {
01153   if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online )
01154     return;
01155 
01156   GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Online );
01157   BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed"));
01158   emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
01159 
01160   if ( kmkernel->msgSender()->sendImmediate() ) {
01161     kmkernel->msgSender()->sendQueued();
01162   }
01163 }
01164 
01165 bool KMKernel::isOffline()
01166 {
01167   if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
01168     return true;
01169   else
01170     return false;
01171 }
01172 
01173 bool KMKernel::askToGoOnline()
01174 {
01175   if ( kmkernel->isOffline() ) {
01176     int rc =
01177     KMessageBox::questionYesNo( KMKernel::self()->mainWin(),
01178                                 i18n("KMail is currently in offline mode. "
01179                                      "How do you want to proceed?"),
01180                                 i18n("Online/Offline"),
01181                                 i18n("Work Online"),
01182                                 i18n("Work Offline"));
01183 
01184     if( rc == KMessageBox::No ) {
01185       return false;
01186     } else {
01187       kmkernel->resumeNetworkJobs();
01188     }
01189   }
01190   return true;
01191 }
01192 
01193 /********************************************************************/
01194 /*                        Kernel methods                            */
01195 /********************************************************************/
01196 
01197 void KMKernel::quit()
01198 {
01199   // Called when all windows are closed. Will take care of compacting,
01200   // sending... should handle session management too!!
01201 }
01202   /* TODO later:
01203    Asuming that:
01204      - msgsender is nonblocking
01205        (our own, QSocketNotifier based. Pops up errors and sends signal
01206         senderFinished when done)
01207 
01208    o If we are getting mail, stop it (but dont lose something!)
01209          [Done already, see mailCheckAborted]
01210    o If we are sending mail, go on UNLESS this was called by SM,
01211        in which case stop ASAP that too (can we warn? should we continue
01212        on next start?)
01213    o If we are compacting, or expunging, go on UNLESS this was SM call.
01214        In that case stop compacting ASAP and continue on next start, before
01215        touching any folders. [Not needed anymore with CompactionJob]
01216 
01217    KMKernel::quit ()
01218    {
01219      SM call?
01220        if compacting, stop;
01221        if sending, stop;
01222        if receiving, stop;
01223        Windows will take care of themselves (composer should dump
01224         its messages, if any but not in deadMail)
01225        declare us ready for the End of the Session
01226 
01227      No, normal quit call
01228        All windows are off. Anything to do, should compact or sender sends?
01229          Yes, maybe put an icon in panel as a sign of life
01230          if sender sending, connect us to his finished slot, declare us ready
01231                             for quit and wait for senderFinished
01232          if not, Folder manager, go compact sent-mail and outbox
01233 }                (= call slotFinished())
01234 
01235 void KMKernel::slotSenderFinished()
01236 {
01237   good, Folder manager go compact sent-mail and outbox
01238   clean up stage1 (release folders and config, unregister from dcop)
01239     -- another kmail may start now ---
01240   kapp->quit();
01241 }
01242 */
01243 
01244 
01245 /********************************************************************/
01246 /*            Init, Exit, and handler  methods                      */
01247 /********************************************************************/
01248 void KMKernel::testDir(const char *_name)
01249 {
01250   QString foldersPath = QDir::homeDirPath() + QString( _name );
01251   QFileInfo info( foldersPath );
01252   if ( !info.exists() ) {
01253     if ( ::mkdir( QFile::encodeName( foldersPath ) , S_IRWXU ) == -1 ) {
01254       KMessageBox::sorry(0, i18n("KMail could not create folder '%1';\n"
01255                                  "please make sure that you can view and "
01256                                  "modify the content of the folder '%2'.")
01257                             .arg( foldersPath ).arg( QDir::homeDirPath() ) );
01258       ::exit(-1);
01259     }
01260   }
01261   if ( !info.isDir() || !info.isReadable() || !info.isWritable() ) {
01262     KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
01263                                "incorrect;\n"
01264                                "please make sure that you can view and modify "
01265                                "the content of this folder.")
01266                           .arg( foldersPath ) );
01267     ::exit(-1);
01268   }
01269 }
01270 
01271 
01272 //-----------------------------------------------------------------------------
01273 // Open a composer for each message found in the dead.letter folder
01274 void KMKernel::recoverDeadLetters()
01275 {
01276   const QString pathName = localDataPath();
01277   QDir dir( pathName );
01278   if ( !dir.exists( "autosave" ) )
01279     return;
01280 
01281   KMFolder folder( 0, pathName + "autosave", KMFolderTypeMaildir, false /* no index */ );
01282   const int rc = folder.open();
01283   if ( rc ) {
01284     perror( "cannot open autosave folder" );
01285     return;
01286   }
01287 
01288   const int num = folder.count();
01289   for ( int i = 0; i < num; i++ ) {
01290     KMMessage *msg = folder.take( 0 );
01291     if ( msg ) {
01292       KMail::Composer * win = KMail::makeComposer();
01293       win->setMsg( msg, false, false, true );
01294       win->setAutoSaveFilename( msg->fileName() );
01295       win->show();
01296     }
01297   }
01298   folder.close();
01299 }
01300 
01301 //-----------------------------------------------------------------------------
01302 void KMKernel::initFolders(KConfig* cfg)
01303 {
01304   QString name;
01305 
01306   name = cfg->readEntry("inboxFolder");
01307 
01308   // Currently the folder manager cannot manage folders which are not
01309   // in the base folder directory.
01310   //if (name.isEmpty()) name = getenv("MAIL");
01311 
01312   if (name.isEmpty()) name = I18N_NOOP("inbox");
01313 
01314   the_inboxFolder  = (KMFolder*)the_folderMgr->findOrCreate(name);
01315 
01316   if (the_inboxFolder->canAccess() != 0) {
01317     emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
01318   }
01319 
01320   the_inboxFolder->setSystemFolder(TRUE);
01321   if ( the_inboxFolder->userWhoField().isEmpty() )
01322     the_inboxFolder->setUserWhoField( QString::null );
01323   // inboxFolder->open();
01324 
01325   the_outboxFolder = the_folderMgr->findOrCreate(cfg->readEntry("outboxFolder", I18N_NOOP("outbox")));
01326   if (the_outboxFolder->canAccess() != 0) {
01327     emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
01328   }
01329   the_outboxFolder->setNoChildren(true);
01330 
01331   the_outboxFolder->setSystemFolder(TRUE);
01332   if ( the_outboxFolder->userWhoField().isEmpty() )
01333     the_outboxFolder->setUserWhoField( QString::null );
01334   /* Nuke the oubox's index file, to make sure that no ghost messages are in
01335    * it from a previous crash. Ghost messages happen in the outbox because it
01336    * the only folder where messages enter and leave within 5 seconds, which is
01337    * the leniency period for index invalidation. Since the number of mails in
01338    * this folder is expected to be very small, we can live with regenerating
01339    * the index on each start to be on the save side. */
01340   //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir )
01341   //  unlink( QFile::encodeName( the_outboxFolder->indexLocation() ) );
01342   the_outboxFolder->open();
01343 
01344   the_sentFolder = the_folderMgr->findOrCreate(cfg->readEntry("sentFolder", I18N_NOOP("sent-mail")));
01345   if (the_sentFolder->canAccess() != 0) {
01346     emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
01347   }
01348   the_sentFolder->setSystemFolder(TRUE);
01349   if ( the_sentFolder->userWhoField().isEmpty() )
01350     the_sentFolder->setUserWhoField( QString::null );
01351   // the_sentFolder->open();
01352 
01353   the_trashFolder  = the_folderMgr->findOrCreate(cfg->readEntry("trashFolder", I18N_NOOP("trash")));
01354   if (the_trashFolder->canAccess() != 0) {
01355     emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
01356   }
01357   the_trashFolder->setSystemFolder(TRUE);
01358   if ( the_trashFolder->userWhoField().isEmpty() )
01359     the_trashFolder->setUserWhoField( QString::null );
01360   // the_trashFolder->open();
01361 
01362   the_draftsFolder = the_folderMgr->findOrCreate(cfg->readEntry("draftsFolder", I18N_NOOP("drafts")));
01363   if (the_draftsFolder->canAccess() != 0) {
01364     emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
01365   }
01366   the_draftsFolder->setSystemFolder(TRUE);
01367   if ( the_draftsFolder->userWhoField().isEmpty() )
01368     the_draftsFolder->setUserWhoField( QString::null );
01369   the_draftsFolder->open();
01370 }
01371 
01372 
01373 void KMKernel::init()
01374 {
01375   the_shuttingDown = false;
01376   the_server_is_ready = false;
01377 
01378   KConfig* cfg = KMKernel::config();
01379 
01380   QDir dir;
01381 
01382   KConfigGroupSaver saver(cfg, "General");
01383   the_firstStart = cfg->readBoolEntry("first-start", true);
01384   cfg->writeEntry("first-start", false);
01385   the_previousVersion = cfg->readEntry("previous-version");
01386   cfg->writeEntry("previous-version", KMAIL_VERSION);
01387   QString foldersPath = cfg->readPathEntry( "folders" );
01388   kdDebug(5006) << k_funcinfo << "foldersPath (from config): '" << foldersPath << "'" << endl;
01389 
01390   if ( foldersPath.isEmpty() ) {
01391     foldersPath = localDataPath() + "mail";
01392     if ( transferMail( foldersPath ) ) {
01393       cfg->writePathEntry( "folders", foldersPath );
01394     }
01395     kdDebug(5006) << k_funcinfo << "foldersPath (after transferMail): '" << foldersPath << "'" << endl;
01396   }
01397 
01398   the_undoStack     = new UndoStack(20);
01399   the_folderMgr     = new KMFolderMgr(foldersPath);
01400   the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
01401   the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
01402 
01403   the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir);
01404   KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
01405   if (lsf)
01406     the_searchFolderMgr->remove( lsf );
01407 
01408   the_acctMgr       = new AccountManager();
01409   the_filterMgr     = new KMFilterMgr();
01410   the_popFilterMgr     = new KMFilterMgr(true);
01411   the_filterActionDict = new KMFilterActionDict;
01412 
01413   // moved up here because KMMessage::stripOffPrefixes is used below -ta
01414   KMMessage::readConfig();
01415   initFolders(cfg);
01416   the_acctMgr->readConfig();
01417   the_filterMgr->readConfig();
01418   the_popFilterMgr->readConfig();
01419   cleanupImapFolders();
01420 
01421   the_msgSender = new KMSender;
01422   the_server_is_ready = true;
01423   imProxy()->initialize();
01424   { // area for config group "Composer"
01425     KConfigGroupSaver saver(cfg, "Composer");
01426     if (cfg->readListEntry("pref-charsets").isEmpty())
01427     {
01428       cfg->writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
01429     }
01430   }
01431   readConfig();
01432   mICalIface->readConfig();
01433   // filterMgr->dump();
01434 #ifdef HAVE_INDEXLIB
01435   the_msgIndex = new KMMsgIndex(this); //create the indexer
01436 #else
01437   the_msgIndex = 0;
01438 #endif
01439 
01440 //#if 0
01441   the_weaver =  new KPIM::ThreadWeaver::Weaver( this );
01442   the_weaverLogger = new KPIM::ThreadWeaver::WeaverThreadLogger(this);
01443   the_weaverLogger->attach (the_weaver);
01444 //#endif
01445 
01446   connect( the_folderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01447            this, SIGNAL( folderRemoved(KMFolder*) ) );
01448   connect( the_dimapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01449            this, SIGNAL( folderRemoved(KMFolder*) ) );
01450   connect( the_imapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01451            this, SIGNAL( folderRemoved(KMFolder*) ) );
01452   connect( the_searchFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01453            this, SIGNAL( folderRemoved(KMFolder*) ) );
01454 
01455   mBackgroundTasksTimer = new QTimer( this );
01456   connect( mBackgroundTasksTimer, SIGNAL( timeout() ), this, SLOT( slotRunBackgroundTasks() ) );
01457 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
01458   mBackgroundTasksTimer->start( 10000, true ); // 10s minute, singleshot
01459 #else
01460   mBackgroundTasksTimer->start( 5 * 60000, true ); // 5 minutes, singleshot
01461 #endif
01462 }
01463 
01464 void KMKernel::readConfig()
01465 {
01466 }
01467 
01468 void KMKernel::cleanupImapFolders()
01469 {
01470   KMAccount *acct = 0;
01471   KMFolderNode *node = the_imapFolderMgr->dir().first();
01472   while (node)
01473   {
01474     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01475               && ( acct->type() == "imap" )) )
01476     {
01477       node = the_imapFolderMgr->dir().next();
01478     } else {
01479       KMFolder* folder = static_cast<KMFolder*>(node);
01480       // delete only local
01481       static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true );
01482       the_imapFolderMgr->remove(folder);
01483       node = the_imapFolderMgr->dir().first();
01484     }
01485   }
01486 
01487   node = the_dimapFolderMgr->dir().first();
01488   while (node)
01489   {
01490     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01491               && ( acct->type() == "cachedimap" )) )
01492     {
01493       node = the_dimapFolderMgr->dir().next();
01494     } else {
01495       the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
01496       node = the_dimapFolderMgr->dir().first();
01497     }
01498   }
01499 
01500   the_imapFolderMgr->quiet(true);
01501   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01502   {
01503     KMFolderImap *fld;
01504     KMAcctImap *imapAcct;
01505 
01506     if (acct->type() != "imap") continue;
01507     fld = static_cast<KMFolderImap*>(the_imapFolderMgr
01508       ->findOrCreate(QString::number(acct->id()), false, acct->id())->storage());
01509     fld->setNoContent(true);
01510     fld->folder()->setLabel(acct->name());
01511     imapAcct = static_cast<KMAcctImap*>(acct);
01512     fld->setAccount(imapAcct);
01513     imapAcct->setImapFolder(fld);
01514     fld->close();
01515   }
01516   the_imapFolderMgr->quiet(false);
01517 
01518   the_dimapFolderMgr->quiet( true );
01519   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01520   {
01521     KMFolderCachedImap *cfld = 0;
01522     KMAcctCachedImap *cachedImapAcct;
01523 
01524     if (acct->type() != "cachedimap" ) continue;
01525 
01526     KMFolder* fld = the_dimapFolderMgr->find(QString::number(acct->id()));
01527     if( fld )
01528       cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
01529     if (cfld == 0) {
01530       // Folder doesn't exist yet
01531       cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(QString::number(acct->id()),
01532             false, KMFolderTypeCachedImap)->storage());
01533       if (!cfld) {
01534         KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_dimapFolderMgr->basePath())));
01535         exit(-1);
01536       }
01537       cfld->folder()->setId( acct->id() );
01538     }
01539 
01540     cfld->setNoContent(true);
01541     cfld->folder()->setLabel(acct->name());
01542     cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
01543     cfld->setAccount(cachedImapAcct);
01544     cachedImapAcct->setImapFolder(cfld);
01545     cfld->close();
01546   }
01547   the_dimapFolderMgr->quiet( false );
01548 }
01549 
01550 bool KMKernel::doSessionManagement()
01551 {
01552 
01553   // Do session management
01554   if (kapp->isRestored()){
01555     int n = 1;
01556     while (KMMainWin::canBeRestored(n)){
01557       //only restore main windows! (Matthias);
01558       if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
01559         (new KMMainWin)->restore(n);
01560       n++;
01561     }
01562     return true; // we were restored by SM
01563   }
01564   return false;  // no, we were not restored
01565 }
01566 
01567 void KMKernel::closeAllKMailWindows()
01568 {
01569   QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01570   KMainWindow *window = 0;
01571   while ((window = it.current()) != 0) {
01572     ++it;
01573     if (window->isA("KMMainWindow") ||
01574     window->inherits("KMail::SecondaryWindow"))
01575       window->close( true ); // close and delete the window
01576   }
01577 }
01578 
01579 void KMKernel::cleanup(void)
01580 {
01581   dumpDeadLetters();
01582   the_shuttingDown = true;
01583   closeAllKMailWindows();
01584 
01585   delete the_acctMgr;
01586   the_acctMgr = 0;
01587   delete the_filterMgr;
01588   the_filterMgr = 0;
01589   delete the_msgSender;
01590   the_msgSender = 0;
01591   delete the_filterActionDict;
01592   the_filterActionDict = 0;
01593   delete the_undoStack;
01594   the_undoStack = 0;
01595   delete the_popFilterMgr;
01596   the_popFilterMgr = 0;
01597 
01598 #if 0
01599   delete the_weaver;
01600   the_weaver = 0;
01601 #endif
01602 
01603   KConfig* config =  KMKernel::config();
01604   KConfigGroupSaver saver(config, "General");
01605 
01606   if (the_trashFolder) {
01607 
01608     the_trashFolder->close(TRUE);
01609 
01610     if (config->readBoolEntry("empty-trash-on-exit", true))
01611     {
01612       if ( the_trashFolder->count( true ) > 0 )
01613         the_trashFolder->expunge();
01614     }
01615   }
01616 
01617   mICalIface->cleanup();
01618 
01619   QValueList<QGuardedPtr<KMFolder> > folders;
01620   QStringList strList;
01621   KMFolder *folder;
01622   the_folderMgr->createFolderList(&strList, &folders);
01623   for (int i = 0; folders.at(i) != folders.end(); i++)
01624   {
01625     folder = *folders.at(i);
01626     if (!folder || folder->isDir()) continue;
01627     folder->close(TRUE);
01628   }
01629   strList.clear();
01630   folders.clear();
01631   the_searchFolderMgr->createFolderList(&strList, &folders);
01632   for (int i = 0; folders.at(i) != folders.end(); i++)
01633   {
01634     folder = *folders.at(i);
01635     if (!folder || folder->isDir()) continue;
01636     folder->close(TRUE);
01637   }
01638 
01639   delete the_msgIndex;
01640   the_msgIndex = 0;
01641   delete the_folderMgr;
01642   the_folderMgr = 0;
01643   delete the_imapFolderMgr;
01644   the_imapFolderMgr = 0;
01645   delete the_dimapFolderMgr;
01646   the_dimapFolderMgr = 0;
01647   delete the_searchFolderMgr;
01648   the_searchFolderMgr = 0;
01649   delete mConfigureDialog;
01650   mConfigureDialog = 0;
01651   delete mWin;
01652   mWin = 0;
01653 
01654   if ( RecentAddresses::exists() )
01655     RecentAddresses::self( config )->save( config );
01656   config->sync();
01657 }
01658 
01659 bool KMKernel::transferMail( QString & destinationDir )
01660 {
01661   QString dir;
01662 
01663   // check whether the user has a ~/KMail folder
01664   QFileInfo fi( QDir::home(), "KMail" );
01665   if ( fi.exists() && fi.isDir() ) {
01666     dir = QDir::homeDirPath() + "/KMail";
01667     // the following two lines can be removed once moving mail is reactivated
01668     destinationDir = dir;
01669     return true;
01670   }
01671 
01672   if ( dir.isEmpty() ) {
01673     // check whether the user has a ~/Mail folder
01674     fi.setFile( QDir::home(), "Mail" );
01675     if ( fi.exists() && fi.isDir() &&
01676          QFile::exists( QDir::homeDirPath() + "/Mail/.inbox.index" ) ) {
01677       // there's a ~/Mail folder which seems to be used by KMail (because of the
01678       // index file)
01679       dir = QDir::homeDirPath() + "/Mail";
01680       // the following two lines can be removed once moving mail is reactivated
01681       destinationDir = dir;
01682       return true;
01683     }
01684   }
01685 
01686   if ( dir.isEmpty() ) {
01687     return true; // there's no old mail folder
01688   }
01689 
01690 #if 0
01691   // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved)
01692   const QString kmailName = kapp->aboutData()->programName();
01693   QString msg;
01694   if ( KIO::NetAccess::exists( destinationDir, true, 0 ) ) {
01695     // if destinationDir exists, we need to warn about possible
01696     // overwriting of files. otherwise, we don't have to
01697     msg = i18n( "%1-%3 is the application name, %4-%7 are folder path",
01698                 "<qt>The <i>%4</i> folder exists. "
01699                 "%1 now uses the <i>%5</i> folder for "
01700                 "its messages.<p>"
01701                 "%2 can move the contents of <i>%6<i> into this folder for "
01702                 "you, though this may replace any existing files with "
01703                 "the same name in <i>%7</i>.<p>"
01704                 "<strong>Would you like %3 to move the mail "
01705                 "files now?</strong></qt>" )
01706           .arg( kmailName, kmailName, kmailName )
01707           .arg( dir, destinationDir, dir, destinationDir );
01708   }
01709   else {
01710     msg = i18n( "%1-%3 is the application name, %4-%6 are folder path",
01711                 "<qt>The <i>%4</i> folder exists. "
01712                 "%1 now uses the <i>%5</i> folder for "
01713                 "its messages. %2 can move the contents of <i>%6</i> into "
01714                 "this folder for you.<p>"
01715                 "<strong>Would you like %3 to move the mail "
01716                 "files now?</strong></qt>" )
01717           .arg( kmailName, kmailName, kmailName )
01718           .arg( dir, destinationDir, dir );
01719   }
01720   QString title = i18n( "Migrate Mail Files?" );
01721   QString buttonText = i18n( "Move" );
01722 
01723   if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) ==
01724        KMessageBox::No ) {
01725     destinationDir = dir;
01726     return true;
01727   }
01728 
01729   if ( !KIO::NetAccess::move( dir, destinationDir ) ) {
01730     kdDebug(5006) << k_funcinfo << "Moving " << dir << " to " << destinationDir << " failed: " << KIO::NetAccess::lastErrorString() << endl;
01731     kdDebug(5006) << k_funcinfo << "Deleting " << destinationDir << endl;
01732     KIO::NetAccess::del( destinationDir, 0 );
01733     destinationDir = dir;
01734     return false;
01735   }
01736 #endif
01737 
01738   return true;
01739 }
01740 
01741 
01742 void KMKernel::ungrabPtrKb(void)
01743 {
01744   if(!KMainWindow::memberList) return;
01745   QWidget* widg = KMainWindow::memberList->first();
01746   Display* dpy;
01747 
01748   if (!widg) return;
01749   dpy = widg->x11Display();
01750   XUngrabKeyboard(dpy, CurrentTime);
01751   XUngrabPointer(dpy, CurrentTime);
01752 }
01753 
01754 
01755 // Message handler
01756 void KMKernel::kmailMsgHandler(QtMsgType aType, const char* aMsg)
01757 {
01758   static int recurse=-1;
01759 
01760   recurse++;
01761 
01762   switch (aType)
01763   {
01764   case QtDebugMsg:
01765   case QtWarningMsg:
01766     kdDebug(5006) << aMsg << endl;
01767     break;
01768 
01769   case QtFatalMsg: // Hm, what about using kdFatal() here?
01770     ungrabPtrKb();
01771     kdDebug(5006) << kapp->caption() << " fatal error "
01772           << aMsg << endl;
01773     KMessageBox::error(0, aMsg);
01774     abort();
01775   }
01776 
01777   recurse--;
01778 }
01779 
01780 
01781 void KMKernel::dumpDeadLetters()
01782 {
01783   if ( shuttingDown() )
01784     return; //All documents should be saved before shutting down is set!
01785 
01786   // make all composer windows autosave their contents
01787   if ( !KMainWindow::memberList )
01788     return;
01789 
01790   for ( QPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it )
01791     if ( KMail::Composer * win = ::qt_cast<KMail::Composer*>( it.current() ) )
01792       win->autoSaveMessage();
01793 }
01794 
01795 
01796 
01797 void KMKernel::action(bool mailto, bool check, const QString &to,
01798                       const QString &cc, const QString &bcc,
01799                       const QString &subj, const QString &body,
01800                       const KURL &messageFile,
01801                       const KURL::List &attachURLs)
01802 {
01803   if (mailto)
01804     openComposer (to, cc, bcc, subj, body, 0, messageFile, attachURLs);
01805   else
01806     openReader( check );
01807 
01808   if (check)
01809     checkMail();
01810   //Anything else?
01811 }
01812 
01813 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KURL &aURL,
01814   bool overwrite)
01815 {
01816   // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
01817   KIO::Job *job = KIO::put(aURL, -1, overwrite, FALSE);
01818   putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
01819   mPutJobs.insert(job, pd);
01820   connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
01821     SLOT(slotDataReq(KIO::Job*,QByteArray&)));
01822   connect(job, SIGNAL(result(KIO::Job*)),
01823     SLOT(slotResult(KIO::Job*)));
01824 }
01825 
01826 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
01827 {
01828   // send the data in 64 KB chunks
01829   const int MAX_CHUNK_SIZE = 64*1024;
01830   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01831   assert(it != mPutJobs.end());
01832   int remainingBytes = (*it).data.size() - (*it).offset;
01833   if( remainingBytes > MAX_CHUNK_SIZE )
01834   {
01835     // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
01836     data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
01837     (*it).offset += MAX_CHUNK_SIZE;
01838     //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes ("
01839     //                << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
01840   }
01841   else
01842   {
01843     // send the remaining bytes to the receiver (deep copy)
01844     data.duplicate( (*it).data.data() + (*it).offset, remainingBytes );
01845     (*it).data = QByteArray();
01846     (*it).offset = 0;
01847     //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n";
01848   }
01849 }
01850 
01851 void KMKernel::slotResult(KIO::Job *job)
01852 {
01853   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01854   assert(it != mPutJobs.end());
01855   if (job->error())
01856   {
01857     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
01858     {
01859       if (KMessageBox::warningContinueCancel(0,
01860         i18n("File %1 exists.\nDo you want to replace it?")
01861         .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace"))
01862         == KMessageBox::Continue)
01863         byteArrayToRemoteFile((*it).data, (*it).url, TRUE);
01864     }
01865     else job->showErrorDialog();
01866   }
01867   mPutJobs.remove(it);
01868 }
01869 
01870 void KMKernel::slotRequestConfigSync() {
01871   // ### FIXME: delay as promised in the kdoc of this function ;-)
01872   KMKernel::config()->sync();
01873 }
01874 
01875 void KMKernel::slotShowConfigurationDialog()
01876 {
01877   if( !mConfigureDialog ) {
01878     mConfigureDialog = new ConfigureDialog( 0, "configure", false );
01879     connect( mConfigureDialog, SIGNAL( configCommitted() ),
01880              this, SLOT( slotConfigChanged() ) );
01881   }
01882 
01883   if( mConfigureDialog->isHidden() )
01884     mConfigureDialog->show();
01885   else
01886     mConfigureDialog->raise();
01887 }
01888 
01889 void KMKernel::slotConfigChanged()
01890 {
01891   readConfig();
01892   emit configChanged();
01893 }
01894 
01895 //-------------------------------------------------------------------------------
01896 //static
01897 QString KMKernel::localDataPath()
01898 {
01899   return locateLocal( "data", "kmail/" );
01900 }
01901 
01902 //-------------------------------------------------------------------------------
01903 
01904 bool KMKernel::haveSystemTrayApplet()
01905 {
01906   return !systemTrayApplets.isEmpty();
01907 }
01908 
01909 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet )
01910 {
01911   if ( systemTrayApplets.findIndex( applet ) == -1 ) {
01912     systemTrayApplets.append( applet );
01913     return true;
01914   }
01915   else
01916     return false;
01917 }
01918 
01919 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet )
01920 {
01921   QValueList<const KSystemTray*>::iterator it =
01922     systemTrayApplets.find( applet );
01923   if ( it != systemTrayApplets.end() ) {
01924     systemTrayApplets.remove( it );
01925     return true;
01926   }
01927   else
01928     return false;
01929 }
01930 
01931 void KMKernel::emergencyExit( const QString& reason )
01932 {
01933   QString mesg;
01934   if ( reason.length() == 0 ) {
01935     mesg = i18n("KMail encountered a fatal error and will terminate now");
01936   }
01937   else {
01938     mesg = i18n("KMail encountered a fatal error and will "
01939                       "terminate now.\nThe error was:\n%1").arg( reason );
01940   }
01941 
01942   kdWarning() << mesg << endl;
01943   KNotifyClient::userEvent( 0, mesg, KNotifyClient::Messagebox, KNotifyClient::Error );
01944 
01945   ::exit(1);
01946 }
01947 
01951 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
01952 {
01953   assert( folder );
01954   if ( folder == the_outboxFolder )
01955     return true;
01956   return folderIsDrafts( folder );
01957 }
01958 
01959 bool KMKernel::folderIsDrafts(const KMFolder * folder)
01960 {
01961   assert( folder );
01962   if ( folder == the_draftsFolder )
01963     return true;
01964 
01965   QString idString = folder->idString();
01966   if ( idString.isEmpty() ) return false;
01967 
01968   // search the identities if the folder matches the drafts-folder
01969   const KPIM::IdentityManager * im = identityManager();
01970   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
01971     if ( (*it).drafts() == idString ) return true;
01972   return false;
01973 }
01974 
01975 bool KMKernel::folderIsTrash(KMFolder * folder)
01976 {
01977   assert(folder);
01978   if (folder == the_trashFolder) return true;
01979   QStringList actList = acctMgr()->getAccounts();
01980   QStringList::Iterator it( actList.begin() );
01981   for( ; it != actList.end() ; ++it ) {
01982     KMAccount* act = acctMgr()->findByName( *it );
01983     if ( act && ( act->trash() == folder->idString() ) )
01984       return true;
01985   }
01986   return false;
01987 }
01988 
01989 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
01990 {
01991   assert( folder );
01992   if ( folder == the_sentFolder )
01993     return true;
01994 
01995   QString idString = folder->idString();
01996   if ( idString.isEmpty() ) return false;
01997 
01998   // search the identities if the folder matches the sent-folder
01999   const KPIM::IdentityManager * im = identityManager();
02000   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
02001     if ( (*it).fcc() == idString ) return true;
02002   return false;
02003 }
02004 
02005 KPIM::IdentityManager * KMKernel::identityManager() {
02006   if ( !mIdentityManager ) {
02007     kdDebug(5006) << "instantating KPIM::IdentityManager" << endl;
02008     mIdentityManager = new KPIM::IdentityManager( false, this, "mIdentityManager" );
02009   }
02010   return mIdentityManager;
02011 }
02012 
02013 KMMsgIndex *KMKernel::msgIndex()
02014 {
02015     return the_msgIndex;
02016 }
02017 
02018 KMainWindow* KMKernel::mainWin()
02019 {
02020   if (KMainWindow::memberList) {
02021     KMainWindow *kmWin = 0;
02022 
02023     // First look for a KMMainWin.
02024     for (kmWin = KMainWindow::memberList->first(); kmWin;
02025          kmWin = KMainWindow::memberList->next())
02026       if (kmWin->isA("KMMainWin"))
02027         return kmWin;
02028 
02029     // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
02030     // case we are running inside Kontact) because we anyway only need
02031     // it for modal message boxes and for KNotify events.
02032     kmWin = KMainWindow::memberList->first();
02033     if ( kmWin )
02034       return kmWin;
02035   }
02036 
02037   // There's not a single KMainWindow. Create a KMMainWin.
02038   // This could happen if we want to pop up an error message
02039   // while we are still doing the startup wizard and no other
02040   // KMainWindow is running.
02041   mWin = new KMMainWin;
02042   return mWin;
02043 }
02044 
02045 
02049 void KMKernel::slotEmptyTrash()
02050 {
02051   QString title = i18n("Empty Trash");
02052   QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
02053   if (KMessageBox::warningContinueCancel(0, text, title,
02054                                          KStdGuiItem::cont(), "confirm_empty_trash")
02055       != KMessageBox::Continue)
02056   {
02057     return;
02058   }
02059 
02060   for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
02061   {
02062     KMFolder* trash = findFolderById(acct->trash());
02063     if (trash)
02064     {
02065       trash->expunge();
02066     }
02067   }
02068 }
02069 
02070 KConfig* KMKernel::config()
02071 {
02072   assert(mySelf);
02073   if (!mySelf->mConfig)
02074   {
02075     mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
02076     // Check that all updates have been run on the config file:
02077     KMail::checkConfigUpdates();
02078   }
02079   return mySelf->mConfig;
02080 }
02081 
02082 KMailICalIfaceImpl& KMKernel::iCalIface()
02083 {
02084   assert( mICalIface );
02085   return *mICalIface;
02086 }
02087 
02088 void KMKernel::selectFolder( QString folderPath )
02089 {
02090   kdDebug(5006)<<"Selecting a folder "<<folderPath<<endl;
02091   const QString localPrefix = "/Local";
02092   KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
02093   if ( !folder && folderPath.startsWith( localPrefix ) )
02094     folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
02095   if ( !folder )
02096     folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
02097   if ( !folder )
02098     folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
02099   Q_ASSERT( folder );
02100 
02101   KMMainWidget *widget = getKMMainWidget();
02102   Q_ASSERT( widget );
02103   if ( !widget )
02104     return;
02105 
02106   KMFolderTree *tree = widget->folderTree();
02107   tree->doFolderSelected( tree->indexOfFolder( folder ) );
02108   tree->ensureItemVisible( tree->indexOfFolder( folder ) );
02109 }
02110 
02111 KMMainWidget *KMKernel::getKMMainWidget()
02112 {
02113   //This could definitely use a speadup
02114   QWidgetList *l = kapp->topLevelWidgets();
02115   QWidgetListIt it( *l );
02116   QWidget *wid;
02117 
02118   while ( ( wid = it.current() ) != 0 ) {
02119     ++it;
02120     QObjectList *l2 = wid->topLevelWidget()->queryList( "KMMainWidget" );
02121     if (l2 && l2->first()) {
02122       KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2->first() );
02123       Q_ASSERT( kmmw );
02124       delete l2;
02125       delete l;
02126       return kmmw;
02127     }
02128     delete l2;
02129   }
02130   delete l;
02131   return 0;
02132 }
02133 
02134 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
02135 {
02136   // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
02137   // a stable kmail release goes out with a nasty bug in CompactionJob...
02138   KConfigGroup generalGroup( config(), "General" );
02139 
02140   if ( generalGroup.readBoolEntry( "auto-expiring", true ) ) {
02141     the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02142     the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02143     the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02144     // the_searchFolderMgr: no expiry there
02145   }
02146 
02147   if ( generalGroup.readBoolEntry( "auto-compaction", true ) ) {
02148     the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
02149     // the_imapFolderMgr: no compaction
02150     the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
02151     // the_searchFolderMgr: no compaction
02152   }
02153 
02154 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
02155   mBackgroundTasksTimer->start( 60 * 1000, true ); // check again in 1 minute
02156 #else
02157   mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours
02158 #endif
02159 
02160 }
02161 
02162 void KMKernel::expireAllFoldersNow() // called by the GUI
02163 {
02164   the_folderMgr->expireAllFolders( true /*immediate*/ );
02165   the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
02166   the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
02167 }
02168 
02169 void KMKernel::compactAllFolders() // called by the GUI
02170 {
02171   the_folderMgr->compactAllFolders( true /*immediate*/ );
02172   //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
02173   the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
02174 }
02175 
02176 KMFolder* KMKernel::findFolderById( const QString& idString )
02177 {
02178   KMFolder * folder = the_folderMgr->findIdString( idString );
02179   if ( !folder )
02180     folder = the_imapFolderMgr->findIdString( idString );
02181   if ( !folder )
02182     folder = the_dimapFolderMgr->findIdString( idString );
02183   if ( !folder )
02184     folder = the_searchFolderMgr->findIdString( idString );
02185   return folder;
02186 }
02187 
02188 ::KIMProxy* KMKernel::imProxy()
02189 {
02190   return KIMProxy::instance( kapp->dcopClient() );
02191 }
02192 
02193 void KMKernel::enableMailCheck()
02194 {
02195   mMailCheckAborted = false;
02196 }
02197 
02198 bool KMKernel::mailCheckAborted() const
02199 {
02200   return mMailCheckAborted;
02201 }
02202 
02203 void KMKernel::abortMailCheck()
02204 {
02205   mMailCheckAborted = true;
02206 }
02207 
02208 bool KMKernel::canQueryClose()
02209 {
02210   if ( KMMainWidget::mainWidgetList() &&
02211        KMMainWidget::mainWidgetList()->count() > 1 )
02212     return true;
02213   KMMainWidget *widget = getKMMainWidget();
02214   if ( !widget )
02215     return true;
02216   KMSystemTray* systray = widget->systray();
02217   if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
02218     systray->hideKMail();
02219     return false;
02220   } else if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
02221     systray->show();
02222     systray->hideKMail();
02223     return false;
02224   }
02225   return true;
02226 }
02227 
02228 void KMKernel::messageCountChanged()
02229 {
02230   mTimeOfLastMessageCountChange = ::time( 0 );
02231 }
02232 
02233 int KMKernel::timeOfLastMessageCountChange() const
02234 {
02235   return mTimeOfLastMessageCountChange;
02236 }
02237 
02238 Wallet *KMKernel::wallet() {
02239   static bool walletOpenFailed = false;
02240   if ( mWallet && mWallet->isOpen() )
02241     return mWallet;
02242 
02243   if ( !Wallet::isEnabled() || walletOpenFailed )
02244     return 0;
02245 
02246   delete mWallet;
02247   mWallet = Wallet::openWallet( Wallet::NetworkWallet(),
02248         getKMMainWidget() ? getKMMainWidget()->topLevelWidget()->winId() : 0 );
02249 
02250   if ( !mWallet ) {
02251     walletOpenFailed = true;
02252     return 0;
02253   }
02254 
02255   if ( !mWallet->hasFolder( "kmail" ) )
02256     mWallet->createFolder( "kmail" );
02257   mWallet->setFolder( "kmail" );
02258   return mWallet;
02259 }
02260 
02261 QValueList< QGuardedPtr<KMFolder> > KMKernel::allFolders()
02262 {
02263   QStringList names;
02264   QValueList<QGuardedPtr<KMFolder> > folders;
02265   folderMgr()->createFolderList(&names, &folders);
02266   imapFolderMgr()->createFolderList(&names, &folders);
02267   dimapFolderMgr()->createFolderList(&names, &folders);
02268   searchFolderMgr()->createFolderList(&names, &folders);
02269 
02270   return folders;
02271 }
02272 
02273 KMFolder *KMKernel::currentFolder() {
02274   KMMainWidget *widget = getKMMainWidget();
02275   KMFolder *folder = 0;
02276   if ( widget && widget->folderTree() ) {
02277     folder = widget->folderTree()->currentFolder();
02278   }
02279   return folder;
02280 }
02281 
02282 // can't be inline, since KMSender isn't known to implement
02283 // KMail::MessageSender outside this .cpp file
02284 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; }
02285 
02286 #include "kmkernel.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys