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