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