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