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   //Needed here, since this function is also called when the configuration
01467   //changes, and the static variables should be updated then - IOF
01468   KMMessage::readConfig();
01469 }
01470 
01471 void KMKernel::cleanupImapFolders()
01472 {
01473   KMAccount *acct = 0;
01474   KMFolderNode *node = the_imapFolderMgr->dir().first();
01475   while (node)
01476   {
01477     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01478               && ( acct->type() == "imap" )) )
01479     {
01480       node = the_imapFolderMgr->dir().next();
01481     } else {
01482       KMFolder* folder = static_cast<KMFolder*>(node);
01483       // delete only local
01484       static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true );
01485       the_imapFolderMgr->remove(folder);
01486       node = the_imapFolderMgr->dir().first();
01487     }
01488   }
01489 
01490   node = the_dimapFolderMgr->dir().first();
01491   while (node)
01492   {
01493     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01494               && ( acct->type() == "cachedimap" )) )
01495     {
01496       node = the_dimapFolderMgr->dir().next();
01497     } else {
01498       the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
01499       node = the_dimapFolderMgr->dir().first();
01500     }
01501   }
01502 
01503   the_imapFolderMgr->quiet(true);
01504   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01505   {
01506     KMFolderImap *fld;
01507     KMAcctImap *imapAcct;
01508 
01509     if (acct->type() != "imap") continue;
01510     fld = static_cast<KMFolderImap*>(the_imapFolderMgr
01511       ->findOrCreate(QString::number(acct->id()), false, acct->id())->storage());
01512     fld->setNoContent(true);
01513     fld->folder()->setLabel(acct->name());
01514     imapAcct = static_cast<KMAcctImap*>(acct);
01515     fld->setAccount(imapAcct);
01516     imapAcct->setImapFolder(fld);
01517     fld->close();
01518   }
01519   the_imapFolderMgr->quiet(false);
01520 
01521   the_dimapFolderMgr->quiet( true );
01522   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01523   {
01524     KMFolderCachedImap *cfld = 0;
01525     KMAcctCachedImap *cachedImapAcct;
01526 
01527     if (acct->type() != "cachedimap" ) continue;
01528 
01529     KMFolder* fld = the_dimapFolderMgr->find(QString::number(acct->id()));
01530     if( fld )
01531       cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
01532     if (cfld == 0) {
01533       // Folder doesn't exist yet
01534       cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(QString::number(acct->id()),
01535             false, KMFolderTypeCachedImap)->storage());
01536       if (!cfld) {
01537         KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_dimapFolderMgr->basePath())));
01538         exit(-1);
01539       }
01540       cfld->folder()->setId( acct->id() );
01541     }
01542 
01543     cfld->setNoContent(true);
01544     cfld->folder()->setLabel(acct->name());
01545     cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
01546     cfld->setAccount(cachedImapAcct);
01547     cachedImapAcct->setImapFolder(cfld);
01548     cfld->close();
01549   }
01550   the_dimapFolderMgr->quiet( false );
01551 }
01552 
01553 bool KMKernel::doSessionManagement()
01554 {
01555 
01556   // Do session management
01557   if (kapp->isRestored()){
01558     int n = 1;
01559     while (KMMainWin::canBeRestored(n)){
01560       //only restore main windows! (Matthias);
01561       if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
01562         (new KMMainWin)->restore(n);
01563       n++;
01564     }
01565     return true; // we were restored by SM
01566   }
01567   return false;  // no, we were not restored
01568 }
01569 
01570 void KMKernel::closeAllKMailWindows()
01571 {
01572   if (!KMainWindow::memberList) return;
01573   QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01574   KMainWindow *window = 0;
01575   while ((window = it.current()) != 0) {
01576     ++it;
01577     if (window->isA("KMMainWindow") ||
01578     window->inherits("KMail::SecondaryWindow"))
01579       window->close( true ); // close and delete the window
01580   }
01581 }
01582 
01583 void KMKernel::cleanup(void)
01584 {
01585   dumpDeadLetters();
01586   the_shuttingDown = true;
01587   closeAllKMailWindows();
01588 
01589   delete the_acctMgr;
01590   the_acctMgr = 0;
01591   delete the_filterMgr;
01592   the_filterMgr = 0;
01593   delete the_msgSender;
01594   the_msgSender = 0;
01595   delete the_filterActionDict;
01596   the_filterActionDict = 0;
01597   delete the_undoStack;
01598   the_undoStack = 0;
01599   delete the_popFilterMgr;
01600   the_popFilterMgr = 0;
01601 
01602 #if 0
01603   delete the_weaver;
01604   the_weaver = 0;
01605 #endif
01606 
01607   KConfig* config =  KMKernel::config();
01608   KConfigGroupSaver saver(config, "General");
01609 
01610   if (the_trashFolder) {
01611 
01612     the_trashFolder->close(TRUE);
01613 
01614     if (config->readBoolEntry("empty-trash-on-exit", true))
01615     {
01616       if ( the_trashFolder->count( true ) > 0 )
01617         the_trashFolder->expunge();
01618     }
01619   }
01620 
01621   mICalIface->cleanup();
01622 
01623   QValueList<QGuardedPtr<KMFolder> > folders;
01624   QStringList strList;
01625   KMFolder *folder;
01626   the_folderMgr->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   strList.clear();
01634   folders.clear();
01635   the_searchFolderMgr->createFolderList(&strList, &folders);
01636   for (int i = 0; folders.at(i) != folders.end(); i++)
01637   {
01638     folder = *folders.at(i);
01639     if (!folder || folder->isDir()) continue;
01640     folder->close(TRUE);
01641   }
01642 
01643   delete the_msgIndex;
01644   the_msgIndex = 0;
01645   delete the_folderMgr;
01646   the_folderMgr = 0;
01647   delete the_imapFolderMgr;
01648   the_imapFolderMgr = 0;
01649   delete the_dimapFolderMgr;
01650   the_dimapFolderMgr = 0;
01651   delete the_searchFolderMgr;
01652   the_searchFolderMgr = 0;
01653   delete mConfigureDialog;
01654   mConfigureDialog = 0;
01655   delete mWin;
01656   mWin = 0;
01657 
01658   if ( RecentAddresses::exists() )
01659     RecentAddresses::self( config )->save( config );
01660   config->sync();
01661 }
01662 
01663 bool KMKernel::transferMail( QString & destinationDir )
01664 {
01665   QString dir;
01666 
01667   // check whether the user has a ~/KMail folder
01668   QFileInfo fi( QDir::home(), "KMail" );
01669   if ( fi.exists() && fi.isDir() ) {
01670     dir = QDir::homeDirPath() + "/KMail";
01671     // the following two lines can be removed once moving mail is reactivated
01672     destinationDir = dir;
01673     return true;
01674   }
01675 
01676   if ( dir.isEmpty() ) {
01677     // check whether the user has a ~/Mail folder
01678     fi.setFile( QDir::home(), "Mail" );
01679     if ( fi.exists() && fi.isDir() &&
01680          QFile::exists( QDir::homeDirPath() + "/Mail/.inbox.index" ) ) {
01681       // there's a ~/Mail folder which seems to be used by KMail (because of the
01682       // index file)
01683       dir = QDir::homeDirPath() + "/Mail";
01684       // the following two lines can be removed once moving mail is reactivated
01685       destinationDir = dir;
01686       return true;
01687     }
01688   }
01689 
01690   if ( dir.isEmpty() ) {
01691     return true; // there's no old mail folder
01692   }
01693 
01694 #if 0
01695   // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved)
01696   const QString kmailName = kapp->aboutData()->programName();
01697   QString msg;
01698   if ( KIO::NetAccess::exists( destinationDir, true, 0 ) ) {
01699     // if destinationDir exists, we need to warn about possible
01700     // overwriting of files. otherwise, we don't have to
01701     msg = i18n( "%1-%3 is the application name, %4-%7 are folder path",
01702                 "<qt>The <i>%4</i> folder exists. "
01703                 "%1 now uses the <i>%5</i> folder for "
01704                 "its messages.<p>"
01705                 "%2 can move the contents of <i>%6<i> into this folder for "
01706                 "you, though this may replace any existing files with "
01707                 "the same name in <i>%7</i>.<p>"
01708                 "<strong>Would you like %3 to move the mail "
01709                 "files now?</strong></qt>" )
01710           .arg( kmailName, kmailName, kmailName )
01711           .arg( dir, destinationDir, dir, destinationDir );
01712   }
01713   else {
01714     msg = i18n( "%1-%3 is the application name, %4-%6 are folder path",
01715                 "<qt>The <i>%4</i> folder exists. "
01716                 "%1 now uses the <i>%5</i> folder for "
01717                 "its messages. %2 can move the contents of <i>%6</i> into "
01718                 "this folder for you.<p>"
01719                 "<strong>Would you like %3 to move the mail "
01720                 "files now?</strong></qt>" )
01721           .arg( kmailName, kmailName, kmailName )
01722           .arg( dir, destinationDir, dir );
01723   }
01724   QString title = i18n( "Migrate Mail Files?" );
01725   QString buttonText = i18n( "Move" );
01726 
01727   if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) ==
01728        KMessageBox::No ) {
01729     destinationDir = dir;
01730     return true;
01731   }
01732 
01733   if ( !KIO::NetAccess::move( dir, destinationDir ) ) {
01734     kdDebug(5006) << k_funcinfo << "Moving " << dir << " to " << destinationDir << " failed: " << KIO::NetAccess::lastErrorString() << endl;
01735     kdDebug(5006) << k_funcinfo << "Deleting " << destinationDir << endl;
01736     KIO::NetAccess::del( destinationDir, 0 );
01737     destinationDir = dir;
01738     return false;
01739   }
01740 #endif
01741 
01742   return true;
01743 }
01744 
01745 
01746 void KMKernel::ungrabPtrKb(void)
01747 {
01748   if(!KMainWindow::memberList) return;
01749   QWidget* widg = KMainWindow::memberList->first();
01750   Display* dpy;
01751 
01752   if (!widg) return;
01753   dpy = widg->x11Display();
01754   XUngrabKeyboard(dpy, CurrentTime);
01755   XUngrabPointer(dpy, CurrentTime);
01756 }
01757 
01758 
01759 // Message handler
01760 void KMKernel::kmailMsgHandler(QtMsgType aType, const char* aMsg)
01761 {
01762   static int recurse=-1;
01763 
01764   recurse++;
01765 
01766   switch (aType)
01767   {
01768   case QtDebugMsg:
01769   case QtWarningMsg:
01770     kdDebug(5006) << aMsg << endl;
01771     break;
01772 
01773   case QtFatalMsg: // Hm, what about using kdFatal() here?
01774     ungrabPtrKb();
01775     kdDebug(5006) << kapp->caption() << " fatal error "
01776           << aMsg << endl;
01777     KMessageBox::error(0, aMsg);
01778     abort();
01779   }
01780 
01781   recurse--;
01782 }
01783 
01784 
01785 void KMKernel::dumpDeadLetters()
01786 {
01787   if ( shuttingDown() )
01788     return; //All documents should be saved before shutting down is set!
01789 
01790   // make all composer windows autosave their contents
01791   if ( !KMainWindow::memberList )
01792     return;
01793 
01794   for ( QPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it )
01795     if ( KMail::Composer * win = ::qt_cast<KMail::Composer*>( it.current() ) )
01796       win->autoSaveMessage();
01797 }
01798 
01799 
01800 
01801 void KMKernel::action(bool mailto, bool check, const QString &to,
01802                       const QString &cc, const QString &bcc,
01803                       const QString &subj, const QString &body,
01804                       const KURL &messageFile,
01805                       const KURL::List &attachURLs)
01806 {
01807   if (mailto)
01808     openComposer (to, cc, bcc, subj, body, 0, messageFile, attachURLs);
01809   else
01810     openReader( check );
01811 
01812   if (check)
01813     checkMail();
01814   //Anything else?
01815 }
01816 
01817 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KURL &aURL,
01818   bool overwrite)
01819 {
01820   // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
01821   KIO::Job *job = KIO::put(aURL, -1, overwrite, FALSE);
01822   putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
01823   mPutJobs.insert(job, pd);
01824   connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
01825     SLOT(slotDataReq(KIO::Job*,QByteArray&)));
01826   connect(job, SIGNAL(result(KIO::Job*)),
01827     SLOT(slotResult(KIO::Job*)));
01828 }
01829 
01830 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
01831 {
01832   // send the data in 64 KB chunks
01833   const int MAX_CHUNK_SIZE = 64*1024;
01834   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01835   assert(it != mPutJobs.end());
01836   int remainingBytes = (*it).data.size() - (*it).offset;
01837   if( remainingBytes > MAX_CHUNK_SIZE )
01838   {
01839     // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
01840     data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
01841     (*it).offset += MAX_CHUNK_SIZE;
01842     //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes ("
01843     //                << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
01844   }
01845   else
01846   {
01847     // send the remaining bytes to the receiver (deep copy)
01848     data.duplicate( (*it).data.data() + (*it).offset, remainingBytes );
01849     (*it).data = QByteArray();
01850     (*it).offset = 0;
01851     //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n";
01852   }
01853 }
01854 
01855 void KMKernel::slotResult(KIO::Job *job)
01856 {
01857   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01858   assert(it != mPutJobs.end());
01859   if (job->error())
01860   {
01861     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
01862     {
01863       if (KMessageBox::warningContinueCancel(0,
01864         i18n("File %1 exists.\nDo you want to replace it?")
01865         .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace"))
01866         == KMessageBox::Continue)
01867         byteArrayToRemoteFile((*it).data, (*it).url, TRUE);
01868     }
01869     else job->showErrorDialog();
01870   }
01871   mPutJobs.remove(it);
01872 }
01873 
01874 void KMKernel::slotRequestConfigSync() {
01875   // ### FIXME: delay as promised in the kdoc of this function ;-)
01876   KMKernel::config()->sync();
01877 }
01878 
01879 void KMKernel::slotShowConfigurationDialog()
01880 {
01881   if( !mConfigureDialog ) {
01882     mConfigureDialog = new ConfigureDialog( 0, "configure", false );
01883     connect( mConfigureDialog, SIGNAL( configCommitted() ),
01884              this, SLOT( slotConfigChanged() ) );
01885   }
01886 
01887   if( mConfigureDialog->isHidden() )
01888     mConfigureDialog->show();
01889   else
01890     mConfigureDialog->raise();
01891 }
01892 
01893 void KMKernel::slotConfigChanged()
01894 {
01895   readConfig();
01896   emit configChanged();
01897 }
01898 
01899 //-------------------------------------------------------------------------------
01900 //static
01901 QString KMKernel::localDataPath()
01902 {
01903   return locateLocal( "data", "kmail/" );
01904 }
01905 
01906 //-------------------------------------------------------------------------------
01907 
01908 bool KMKernel::haveSystemTrayApplet()
01909 {
01910   return !systemTrayApplets.isEmpty();
01911 }
01912 
01913 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet )
01914 {
01915   if ( systemTrayApplets.findIndex( applet ) == -1 ) {
01916     systemTrayApplets.append( applet );
01917     return true;
01918   }
01919   else
01920     return false;
01921 }
01922 
01923 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet )
01924 {
01925   QValueList<const KSystemTray*>::iterator it =
01926     systemTrayApplets.find( applet );
01927   if ( it != systemTrayApplets.end() ) {
01928     systemTrayApplets.remove( it );
01929     return true;
01930   }
01931   else
01932     return false;
01933 }
01934 
01935 void KMKernel::emergencyExit( const QString& reason )
01936 {
01937   QString mesg;
01938   if ( reason.length() == 0 ) {
01939     mesg = i18n("KMail encountered a fatal error and will terminate now");
01940   }
01941   else {
01942     mesg = i18n("KMail encountered a fatal error and will "
01943                       "terminate now.\nThe error was:\n%1").arg( reason );
01944   }
01945 
01946   kdWarning() << mesg << endl;
01947   KNotifyClient::userEvent( 0, mesg, KNotifyClient::Messagebox, KNotifyClient::Error );
01948 
01949   ::exit(1);
01950 }
01951 
01955 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
01956 {
01957   assert( folder );
01958   if ( folder == the_outboxFolder )
01959     return true;
01960   return folderIsDrafts( folder );
01961 }
01962 
01963 bool KMKernel::folderIsDrafts(const KMFolder * folder)
01964 {
01965   assert( folder );
01966   if ( folder == the_draftsFolder )
01967     return true;
01968 
01969   QString idString = folder->idString();
01970   if ( idString.isEmpty() ) return false;
01971 
01972   // search the identities if the folder matches the drafts-folder
01973   const KPIM::IdentityManager * im = identityManager();
01974   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
01975     if ( (*it).drafts() == idString ) return true;
01976   return false;
01977 }
01978 
01979 bool KMKernel::folderIsTrash(KMFolder * folder)
01980 {
01981   assert(folder);
01982   if (folder == the_trashFolder) return true;
01983   QStringList actList = acctMgr()->getAccounts();
01984   QStringList::Iterator it( actList.begin() );
01985   for( ; it != actList.end() ; ++it ) {
01986     KMAccount* act = acctMgr()->findByName( *it );
01987     if ( act && ( act->trash() == folder->idString() ) )
01988       return true;
01989   }
01990   return false;
01991 }
01992 
01993 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
01994 {
01995   assert( folder );
01996   if ( folder == the_sentFolder )
01997     return true;
01998 
01999   QString idString = folder->idString();
02000   if ( idString.isEmpty() ) return false;
02001 
02002   // search the identities if the folder matches the sent-folder
02003   const KPIM::IdentityManager * im = identityManager();
02004   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
02005     if ( (*it).fcc() == idString ) return true;
02006   return false;
02007 }
02008 
02009 KPIM::IdentityManager * KMKernel::identityManager() {
02010   if ( !mIdentityManager ) {
02011     kdDebug(5006) << "instantating KPIM::IdentityManager" << endl;
02012     mIdentityManager = new KPIM::IdentityManager( false, this, "mIdentityManager" );
02013   }
02014   return mIdentityManager;
02015 }
02016 
02017 KMMsgIndex *KMKernel::msgIndex()
02018 {
02019     return the_msgIndex;
02020 }
02021 
02022 KMainWindow* KMKernel::mainWin()
02023 {
02024   if (KMainWindow::memberList) {
02025     KMainWindow *kmWin = 0;
02026 
02027     // First look for a KMMainWin.
02028     for (kmWin = KMainWindow::memberList->first(); kmWin;
02029          kmWin = KMainWindow::memberList->next())
02030       if (kmWin->isA("KMMainWin"))
02031         return kmWin;
02032 
02033     // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
02034     // case we are running inside Kontact) because we anyway only need
02035     // it for modal message boxes and for KNotify events.
02036     kmWin = KMainWindow::memberList->first();
02037     if ( kmWin )
02038       return kmWin;
02039   }
02040 
02041   // There's not a single KMainWindow. Create a KMMainWin.
02042   // This could happen if we want to pop up an error message
02043   // while we are still doing the startup wizard and no other
02044   // KMainWindow is running.
02045   mWin = new KMMainWin;
02046   return mWin;
02047 }
02048 
02049 
02053 void KMKernel::slotEmptyTrash()
02054 {
02055   QString title = i18n("Empty Trash");
02056   QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
02057   if (KMessageBox::warningContinueCancel(0, text, title,
02058                                          KStdGuiItem::cont(), "confirm_empty_trash")
02059       != KMessageBox::Continue)
02060   {
02061     return;
02062   }
02063 
02064   for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
02065   {
02066     KMFolder* trash = findFolderById(acct->trash());
02067     if (trash)
02068     {
02069       trash->expunge();
02070     }
02071   }
02072 }
02073 
02074 KConfig* KMKernel::config()
02075 {
02076   assert(mySelf);
02077   if (!mySelf->mConfig)
02078   {
02079     mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
02080     // Check that all updates have been run on the config file:
02081     KMail::checkConfigUpdates();
02082   }
02083   return mySelf->mConfig;
02084 }
02085 
02086 KMailICalIfaceImpl& KMKernel::iCalIface()
02087 {
02088   assert( mICalIface );
02089   return *mICalIface;
02090 }
02091 
02092 void KMKernel::selectFolder( QString folderPath )
02093 {
02094   kdDebug(5006)<<"Selecting a folder "<<folderPath<<endl;
02095   const QString localPrefix = "/Local";
02096   KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
02097   if ( !folder && folderPath.startsWith( localPrefix ) )
02098     folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
02099   if ( !folder )
02100     folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
02101   if ( !folder )
02102     folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
02103   Q_ASSERT( folder );
02104 
02105   KMMainWidget *widget = getKMMainWidget();
02106   Q_ASSERT( widget );
02107   if ( !widget )
02108     return;
02109 
02110   KMFolderTree *tree = widget->folderTree();
02111   tree->doFolderSelected( tree->indexOfFolder( folder ) );
02112   tree->ensureItemVisible( tree->indexOfFolder( folder ) );
02113 }
02114 
02115 KMMainWidget *KMKernel::getKMMainWidget()
02116 {
02117   //This could definitely use a speadup
02118   QWidgetList *l = kapp->topLevelWidgets();
02119   QWidgetListIt it( *l );
02120   QWidget *wid;
02121 
02122   while ( ( wid = it.current() ) != 0 ) {
02123     ++it;
02124     QObjectList *l2 = wid->topLevelWidget()->queryList( "KMMainWidget" );
02125     if (l2 && l2->first()) {
02126       KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2->first() );
02127       Q_ASSERT( kmmw );
02128       delete l2;
02129       delete l;
02130       return kmmw;
02131     }
02132     delete l2;
02133   }
02134   delete l;
02135   return 0;
02136 }
02137 
02138 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
02139 {
02140   // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
02141   // a stable kmail release goes out with a nasty bug in CompactionJob...
02142   KConfigGroup generalGroup( config(), "General" );
02143 
02144   if ( generalGroup.readBoolEntry( "auto-expiring", true ) ) {
02145     the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02146     the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02147     the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02148     // the_searchFolderMgr: no expiry there
02149   }
02150 
02151   if ( generalGroup.readBoolEntry( "auto-compaction", true ) ) {
02152     the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
02153     // the_imapFolderMgr: no compaction
02154     the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
02155     // the_searchFolderMgr: no compaction
02156   }
02157 
02158 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
02159   mBackgroundTasksTimer->start( 60 * 1000, true ); // check again in 1 minute
02160 #else
02161   mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours
02162 #endif
02163 
02164 }
02165 
02166 void KMKernel::expireAllFoldersNow() // called by the GUI
02167 {
02168   the_folderMgr->expireAllFolders( true /*immediate*/ );
02169   the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
02170   the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
02171 }
02172 
02173 void KMKernel::compactAllFolders() // called by the GUI
02174 {
02175   the_folderMgr->compactAllFolders( true /*immediate*/ );
02176   //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
02177   the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
02178 }
02179 
02180 KMFolder* KMKernel::findFolderById( const QString& idString )
02181 {
02182   KMFolder * folder = the_folderMgr->findIdString( idString );
02183   if ( !folder )
02184     folder = the_imapFolderMgr->findIdString( idString );
02185   if ( !folder )
02186     folder = the_dimapFolderMgr->findIdString( idString );
02187   if ( !folder )
02188     folder = the_searchFolderMgr->findIdString( idString );
02189   return folder;
02190 }
02191 
02192 ::KIMProxy* KMKernel::imProxy()
02193 {
02194   return KIMProxy::instance( kapp->dcopClient() );
02195 }
02196 
02197 void KMKernel::enableMailCheck()
02198 {
02199   mMailCheckAborted = false;
02200 }
02201 
02202 bool KMKernel::mailCheckAborted() const
02203 {
02204   return mMailCheckAborted;
02205 }
02206 
02207 void KMKernel::abortMailCheck()
02208 {
02209   mMailCheckAborted = true;
02210 }
02211 
02212 bool KMKernel::canQueryClose()
02213 {
02214   if ( KMMainWidget::mainWidgetList() &&
02215        KMMainWidget::mainWidgetList()->count() > 1 )
02216     return true;
02217   KMMainWidget *widget = getKMMainWidget();
02218   if ( !widget )
02219     return true;
02220   KMSystemTray* systray = widget->systray();
02221   if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
02222     systray->hideKMail();
02223     return false;
02224   } else if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
02225     systray->show();
02226     systray->hideKMail();
02227     return false;
02228   }
02229   return true;
02230 }
02231 
02232 void KMKernel::messageCountChanged()
02233 {
02234   mTimeOfLastMessageCountChange = ::time( 0 );
02235 }
02236 
02237 int KMKernel::timeOfLastMessageCountChange() const
02238 {
02239   return mTimeOfLastMessageCountChange;
02240 }
02241 
02242 Wallet *KMKernel::wallet() {
02243   static bool walletOpenFailed = false;
02244   if ( mWallet && mWallet->isOpen() )
02245     return mWallet;
02246 
02247   if ( !Wallet::isEnabled() || walletOpenFailed )
02248     return 0;
02249 
02250   delete mWallet;
02251   mWallet = Wallet::openWallet( Wallet::NetworkWallet(),
02252         getKMMainWidget() ? getKMMainWidget()->topLevelWidget()->winId() : 0 );
02253 
02254   if ( !mWallet ) {
02255     walletOpenFailed = true;
02256     return 0;
02257   }
02258 
02259   if ( !mWallet->hasFolder( "kmail" ) )
02260     mWallet->createFolder( "kmail" );
02261   mWallet->setFolder( "kmail" );
02262   return mWallet;
02263 }
02264 
02265 QValueList< QGuardedPtr<KMFolder> > KMKernel::allFolders()
02266 {
02267   QStringList names;
02268   QValueList<QGuardedPtr<KMFolder> > folders;
02269   folderMgr()->createFolderList(&names, &folders);
02270   imapFolderMgr()->createFolderList(&names, &folders);
02271   dimapFolderMgr()->createFolderList(&names, &folders);
02272   searchFolderMgr()->createFolderList(&names, &folders);
02273 
02274   return folders;
02275 }
02276 
02277 KMFolder *KMKernel::currentFolder() {
02278   KMMainWidget *widget = getKMMainWidget();
02279   KMFolder *folder = 0;
02280   if ( widget && widget->folderTree() ) {
02281     folder = widget->folderTree()->currentFolder();
02282   }
02283   return folder;
02284 }
02285 
02286 // can't be inline, since KMSender isn't known to implement
02287 // KMail::MessageSender outside this .cpp file
02288 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; }
02289 
02290 #include "kmkernel.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys