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