kmail

kmkernel.cpp

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