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