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