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