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