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