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   const QString pathName = localDataPath();
01383   QDir dir( pathName );
01384   if ( !dir.exists( "autosave" ) )
01385     return;
01386 
01387   KMFolder folder( 0, pathName + "autosave", KMFolderTypeMaildir, false /* no index */ );
01388   KMFolderOpener openFolder( &folder, "recover" );
01389   if ( !folder.isOpened() ) {
01390     perror( "cannot open autosave folder" );
01391     return;
01392   }
01393 
01394   const int num = folder.count();
01395   for ( int i = 0; i < num; i++ ) {
01396     KMMessage *msg = folder.take( 0 );
01397     if ( msg ) {
01398       KMail::Composer * win = KMail::makeComposer();
01399       win->setMsg( msg, false, false, true );
01400       win->setAutoSaveFilename( msg->fileName() );
01401       win->show();
01402     }
01403   }
01404 }
01405 
01406 //-----------------------------------------------------------------------------
01407 void KMKernel::initFolders(KConfig* cfg)
01408 {
01409   QString name;
01410 
01411   name = cfg->readEntry("inboxFolder");
01412 
01413   // Currently the folder manager cannot manage folders which are not
01414   // in the base folder directory.
01415   //if (name.isEmpty()) name = getenv("MAIL");
01416 
01417   if (name.isEmpty()) name = I18N_NOOP("inbox");
01418 
01419   the_inboxFolder  = (KMFolder*)the_folderMgr->findOrCreate(name);
01420 
01421   if (the_inboxFolder->canAccess() != 0) {
01422     emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
01423   }
01424 
01425   the_inboxFolder->setSystemFolder(true);
01426   if ( the_inboxFolder->userWhoField().isEmpty() )
01427     the_inboxFolder->setUserWhoField( QString::null );
01428   // inboxFolder->open();
01429 
01430   the_outboxFolder = the_folderMgr->findOrCreate(cfg->readEntry("outboxFolder", I18N_NOOP("outbox")));
01431   if (the_outboxFolder->canAccess() != 0) {
01432     emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
01433   }
01434   the_outboxFolder->setNoChildren(true);
01435 
01436   the_outboxFolder->setSystemFolder(true);
01437   if ( the_outboxFolder->userWhoField().isEmpty() )
01438     the_outboxFolder->setUserWhoField( QString::null );
01439   /* Nuke the oubox's index file, to make sure that no ghost messages are in
01440    * it from a previous crash. Ghost messages happen in the outbox because it
01441    * the only folder where messages enter and leave within 5 seconds, which is
01442    * the leniency period for index invalidation. Since the number of mails in
01443    * this folder is expected to be very small, we can live with regenerating
01444    * the index on each start to be on the save side. */
01445   //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir )
01446   //  unlink( QFile::encodeName( the_outboxFolder->indexLocation() ) );
01447   the_outboxFolder->open("kmkernel");
01448 
01449   the_sentFolder = the_folderMgr->findOrCreate(cfg->readEntry("sentFolder", I18N_NOOP("sent-mail")));
01450   if (the_sentFolder->canAccess() != 0) {
01451     emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
01452   }
01453   the_sentFolder->setSystemFolder(true);
01454   if ( the_sentFolder->userWhoField().isEmpty() )
01455     the_sentFolder->setUserWhoField( QString::null );
01456   // the_sentFolder->open();
01457 
01458   the_trashFolder  = the_folderMgr->findOrCreate(cfg->readEntry("trashFolder", I18N_NOOP("trash")));
01459   if (the_trashFolder->canAccess() != 0) {
01460     emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
01461   }
01462   the_trashFolder->setSystemFolder( true );
01463   if ( the_trashFolder->userWhoField().isEmpty() )
01464     the_trashFolder->setUserWhoField( QString::null );
01465   // the_trashFolder->open();
01466 
01467   the_draftsFolder = the_folderMgr->findOrCreate(cfg->readEntry("draftsFolder", I18N_NOOP("drafts")));
01468   if (the_draftsFolder->canAccess() != 0) {
01469     emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
01470   }
01471   the_draftsFolder->setSystemFolder( true );
01472   if ( the_draftsFolder->userWhoField().isEmpty() )
01473     the_draftsFolder->setUserWhoField( QString::null );
01474   the_draftsFolder->open("kmkernel");
01475 
01476   the_templatesFolder =
01477     the_folderMgr->findOrCreate( cfg->readEntry( "templatesFolder",
01478                                                  I18N_NOOP("templates") ) );
01479   if ( the_templatesFolder->canAccess() != 0 ) {
01480     emergencyExit( i18n("You do not have read/write permission to your templates folder.") );
01481   }
01482   the_templatesFolder->setSystemFolder( true );
01483   if ( the_templatesFolder->userWhoField().isEmpty() )
01484     the_templatesFolder->setUserWhoField( QString::null );
01485   the_templatesFolder->open("kmkernel");
01486 }
01487 
01488 
01489 void KMKernel::init()
01490 {
01491   the_shuttingDown = false;
01492   the_server_is_ready = false;
01493 
01494   KConfig* cfg = KMKernel::config();
01495 
01496   QDir dir;
01497 
01498   KConfigGroupSaver saver(cfg, "General");
01499   the_firstStart = cfg->readBoolEntry("first-start", true);
01500   cfg->writeEntry("first-start", false);
01501   the_previousVersion = cfg->readEntry("previous-version");
01502   cfg->writeEntry("previous-version", KMAIL_VERSION);
01503   QString foldersPath = cfg->readPathEntry( "folders" );
01504   kdDebug(5006) << k_funcinfo << "foldersPath (from config): '" << foldersPath << "'" << endl;
01505 
01506   if ( foldersPath.isEmpty() ) {
01507     foldersPath = localDataPath() + "mail";
01508     if ( transferMail( foldersPath ) ) {
01509       cfg->writePathEntry( "folders", foldersPath );
01510     }
01511     kdDebug(5006) << k_funcinfo << "foldersPath (after transferMail): '" << foldersPath << "'" << endl;
01512   }
01513 
01514   // moved up here because KMMessage::stripOffPrefixes is used below
01515   KMMessage::readConfig();
01516 
01517   the_undoStack     = new UndoStack(20);
01518   the_folderMgr     = new KMFolderMgr(foldersPath);
01519   the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
01520   the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
01521 
01522   the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir);
01523   KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
01524   if (lsf)
01525     the_searchFolderMgr->remove( lsf );
01526 
01527   the_acctMgr       = new AccountManager();
01528   the_filterMgr     = new KMFilterMgr();
01529   the_popFilterMgr     = new KMFilterMgr(true);
01530   the_filterActionDict = new KMFilterActionDict;
01531 
01532   initFolders(cfg);
01533   the_acctMgr->readConfig();
01534   the_filterMgr->readConfig();
01535   the_popFilterMgr->readConfig();
01536   cleanupImapFolders();
01537 
01538   the_msgSender = new KMSender;
01539   the_server_is_ready = true;
01540   imProxy()->initialize();
01541   { // area for config group "Composer"
01542     KConfigGroupSaver saver(cfg, "Composer");
01543     if (cfg->readListEntry("pref-charsets").isEmpty())
01544     {
01545       cfg->writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
01546     }
01547   }
01548   readConfig();
01549   mICalIface->readConfig();
01550   // filterMgr->dump();
01551 #ifdef HAVE_INDEXLIB
01552   the_msgIndex = new KMMsgIndex(this); //create the indexer
01553 #else
01554   the_msgIndex = 0;
01555 #endif
01556 
01557 //#if 0
01558   the_weaver =  new KPIM::ThreadWeaver::Weaver( this );
01559   the_weaverLogger = new KPIM::ThreadWeaver::WeaverThreadLogger(this);
01560   the_weaverLogger->attach (the_weaver);
01561 //#endif
01562 
01563   connect( the_folderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01564            this, SIGNAL( folderRemoved(KMFolder*) ) );
01565   connect( the_dimapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01566            this, SIGNAL( folderRemoved(KMFolder*) ) );
01567   connect( the_imapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01568            this, SIGNAL( folderRemoved(KMFolder*) ) );
01569   connect( the_searchFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01570            this, SIGNAL( folderRemoved(KMFolder*) ) );
01571 
01572   mBackgroundTasksTimer = new QTimer( this, "mBackgroundTasksTimer" );
01573   connect( mBackgroundTasksTimer, SIGNAL( timeout() ), this, SLOT( slotRunBackgroundTasks() ) );
01574 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
01575   mBackgroundTasksTimer->start( 10000, true ); // 10s, singleshot
01576 #else
01577   mBackgroundTasksTimer->start( 5 * 60000, true ); // 5 minutes, singleshot
01578 #endif
01579 }
01580 
01581 void KMKernel::readConfig()
01582 {
01583   //Needed here, since this function is also called when the configuration
01584   //changes, and the static variables should be updated then - IOF
01585   KMMessage::readConfig();
01586 }
01587 
01588 void KMKernel::cleanupImapFolders()
01589 {
01590   KMAccount *acct = 0;
01591   KMFolderNode *node = the_imapFolderMgr->dir().first();
01592   while (node)
01593   {
01594     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01595               && ( acct->type() == "imap" )) )
01596     {
01597       node = the_imapFolderMgr->dir().next();
01598     } else {
01599       KMFolder* folder = static_cast<KMFolder*>(node);
01600       // delete only local
01601       static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true );
01602       the_imapFolderMgr->remove(folder);
01603       node = the_imapFolderMgr->dir().first();
01604     }
01605   }
01606 
01607   node = the_dimapFolderMgr->dir().first();
01608   while (node)
01609   {
01610     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01611               && ( acct->type() == "cachedimap" )) )
01612     {
01613       node = the_dimapFolderMgr->dir().next();
01614     } else {
01615       the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
01616       node = the_dimapFolderMgr->dir().first();
01617     }
01618   }
01619 
01620   the_imapFolderMgr->quiet(true);
01621   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01622   {
01623     KMFolderImap *fld;
01624     KMAcctImap *imapAcct;
01625 
01626     if (acct->type() != "imap") continue;
01627     fld = static_cast<KMFolderImap*>(the_imapFolderMgr
01628       ->findOrCreate(QString::number(acct->id()), false, acct->id())->storage());
01629     fld->setNoContent(true);
01630     fld->folder()->setLabel(acct->name());
01631     imapAcct = static_cast<KMAcctImap*>(acct);
01632     fld->setAccount(imapAcct);
01633     imapAcct->setImapFolder(fld);
01634     fld->close( "kernel", true );
01635   }
01636   the_imapFolderMgr->quiet(false);
01637 
01638   the_dimapFolderMgr->quiet( true );
01639   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01640   {
01641     KMFolderCachedImap *cfld = 0;
01642     KMAcctCachedImap *cachedImapAcct;
01643 
01644     if (acct->type() != "cachedimap" ) continue;
01645 
01646     KMFolder* fld = the_dimapFolderMgr->find(QString::number(acct->id()));
01647     if( fld )
01648       cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
01649     if (cfld == 0) {
01650       // Folder doesn't exist yet
01651       cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(QString::number(acct->id()),
01652             false, KMFolderTypeCachedImap)->storage());
01653       if (!cfld) {
01654         KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_dimapFolderMgr->basePath())));
01655         exit(-1);
01656       }
01657       cfld->folder()->setId( acct->id() );
01658     }
01659 
01660     cfld->setNoContent(true);
01661     cfld->folder()->setLabel(acct->name());
01662     cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
01663     cfld->setAccount(cachedImapAcct);
01664     cachedImapAcct->setImapFolder(cfld);
01665     cfld->close("kmkernel");
01666   }
01667   the_dimapFolderMgr->quiet( false );
01668 }
01669 
01670 bool KMKernel::doSessionManagement()
01671 {
01672 
01673   // Do session management
01674   if (kapp->isRestored()){
01675     int n = 1;
01676     while (KMMainWin::canBeRestored(n)){
01677       //only restore main windows! (Matthias);
01678       if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
01679         (new KMMainWin)->restore(n);
01680       n++;
01681     }
01682     return true; // we were restored by SM
01683   }
01684   return false;  // no, we were not restored
01685 }
01686 
01687 void KMKernel::closeAllKMailWindows()
01688 {
01689   if (!KMainWindow::memberList) return;
01690   QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01691   KMainWindow *window = 0;
01692   while ((window = it.current()) != 0) {
01693     ++it;
01694     if (window->isA("KMMainWindow") ||
01695     window->inherits("KMail::SecondaryWindow"))
01696       window->close( true ); // close and delete the window
01697   }
01698 }
01699 
01700 void KMKernel::cleanup(void)
01701 {
01702   dumpDeadLetters();
01703   the_shuttingDown = true;
01704   closeAllKMailWindows();
01705 
01706   delete the_acctMgr;
01707   the_acctMgr = 0;
01708   delete the_filterMgr;
01709   the_filterMgr = 0;
01710   delete the_msgSender;
01711   the_msgSender = 0;
01712   delete the_filterActionDict;
01713   the_filterActionDict = 0;
01714   delete the_undoStack;
01715   the_undoStack = 0;
01716   delete the_popFilterMgr;
01717   the_popFilterMgr = 0;
01718 
01719 #if 0
01720   delete the_weaver;
01721   the_weaver = 0;
01722 #endif
01723 
01724   KConfig* config =  KMKernel::config();
01725   KConfigGroupSaver saver(config, "General");
01726 
01727   if (the_trashFolder) {
01728 
01729     the_trashFolder->close("kmkernel", true);
01730 
01731     if (config->readBoolEntry("empty-trash-on-exit", true))
01732     {
01733       if ( the_trashFolder->count( true ) > 0 )
01734         the_trashFolder->expunge();
01735     }
01736   }
01737 
01738   mICalIface->cleanup();
01739 
01740   QValueList<QGuardedPtr<KMFolder> > folders;
01741   QStringList strList;
01742   KMFolder *folder;
01743   the_folderMgr->createFolderList(&strList, &folders);
01744   for (int i = 0; folders.at(i) != folders.end(); i++)
01745   {
01746     folder = *folders.at(i);
01747     if (!folder || folder->isDir()) continue;
01748     folder->close("kmkernel", true);
01749   }
01750   strList.clear();
01751   folders.clear();
01752   the_searchFolderMgr->createFolderList(&strList, &folders);
01753   for (int i = 0; folders.at(i) != folders.end(); i++)
01754   {
01755     folder = *folders.at(i);
01756     if (!folder || folder->isDir()) continue;
01757     folder->close("kmkernel", true);
01758   }
01759 
01760   delete the_msgIndex;
01761   the_msgIndex = 0;
01762   delete the_folderMgr;
01763   the_folderMgr = 0;
01764   delete the_imapFolderMgr;
01765   the_imapFolderMgr = 0;
01766   delete the_dimapFolderMgr;
01767   the_dimapFolderMgr = 0;
01768   delete the_searchFolderMgr;
01769   the_searchFolderMgr = 0;
01770   delete mConfigureDialog;
01771   mConfigureDialog = 0;
01772   // do not delete, because mWin may point to an existing window
01773   // delete mWin;
01774   mWin = 0;
01775 
01776   if ( RecentAddresses::exists() )
01777     RecentAddresses::self( config )->save( config );
01778   config->sync();
01779 }
01780 
01781 bool KMKernel::transferMail( QString & destinationDir )
01782 {
01783   QString dir;
01784 
01785   // check whether the user has a ~/KMail folder
01786   QFileInfo fi( QDir::home(), "KMail" );
01787   if ( fi.exists() && fi.isDir() ) {
01788     dir = QDir::homeDirPath() + "/KMail";
01789     // the following two lines can be removed once moving mail is reactivated
01790     destinationDir = dir;
01791     return true;
01792   }
01793 
01794   if ( dir.isEmpty() ) {
01795     // check whether the user has a ~/Mail folder
01796     fi.setFile( QDir::home(), "Mail" );
01797     if ( fi.exists() && fi.isDir() &&
01798          QFile::exists( QDir::homeDirPath() + "/Mail/.inbox.index" ) ) {
01799       // there's a ~/Mail folder which seems to be used by KMail (because of the
01800       // index file)
01801       dir = QDir::homeDirPath() + "/Mail";
01802       // the following two lines can be removed once moving mail is reactivated
01803       destinationDir = dir;
01804       return true;
01805     }
01806   }
01807 
01808   if ( dir.isEmpty() ) {
01809     return true; // there's no old mail folder
01810   }
01811 
01812 #if 0
01813   // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved)
01814   const QString kmailName = kapp->aboutData()->programName();
01815   QString msg;
01816   if ( KIO::NetAccess::exists( destinationDir, true, 0 ) ) {
01817     // if destinationDir exists, we need to warn about possible
01818     // overwriting of files. otherwise, we don't have to
01819     msg = i18n( "%1-%3 is the application name, %4-%7 are folder path",
01820                 "<qt>The <i>%4</i> folder exists. "
01821                 "%1 now uses the <i>%5</i> folder for "
01822                 "its messages.<p>"
01823                 "%2 can move the contents of <i>%6<i> into this folder for "
01824                 "you, though this may replace any existing files with "
01825                 "the same name in <i>%7</i>.<p>"
01826                 "<strong>Would you like %3 to move the mail "
01827                 "files now?</strong></qt>" )
01828           .arg( kmailName, kmailName, kmailName )
01829           .arg( dir, destinationDir, dir, destinationDir );
01830   } else {
01831     msg = i18n( "%1-%3 is the application name, %4-%6 are folder path",
01832                 "<qt>The <i>%4</i> folder exists. "
01833                 "%1 now uses the <i>%5</i> folder for "
01834                 "its messages. %2 can move the contents of <i>%6</i> into "
01835                 "this folder for you.<p>"
01836                 "<strong>Would you like %3 to move the mail "
01837                 "files now?</strong></qt>" )
01838           .arg( kmailName, kmailName, kmailName )
01839           .arg( dir, destinationDir, dir );
01840   }
01841   QString title = i18n( "Migrate Mail Files?" );
01842   QString buttonText = i18n( "Move" );
01843 
01844   if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) ==
01845        KMessageBox::No ) {
01846     destinationDir = dir;
01847     return true;
01848   }
01849 
01850   if ( !KIO::NetAccess::move( dir, destinationDir ) ) {
01851     kdDebug(5006) << k_funcinfo << "Moving " << dir << " to " << destinationDir << " failed: " << KIO::NetAccess::lastErrorString() << endl;
01852     kdDebug(5006) << k_funcinfo << "Deleting " << destinationDir << endl;
01853     KIO::NetAccess::del( destinationDir, 0 );
01854     destinationDir = dir;
01855     return false;
01856   }
01857 #endif
01858 
01859   return true;
01860 }
01861 
01862 
01863 void KMKernel::ungrabPtrKb(void)
01864 {
01865   if(!KMainWindow::memberList) return;
01866   QWidget* widg = KMainWindow::memberList->first();
01867   Display* dpy;
01868 
01869   if (!widg) return;
01870   dpy = widg->x11Display();
01871   XUngrabKeyboard(dpy, CurrentTime);
01872   XUngrabPointer(dpy, CurrentTime);
01873 }
01874 
01875 
01876 // Message handler
01877 void KMKernel::kmailMsgHandler(QtMsgType aType, const char* aMsg)
01878 {
01879   static int recurse=-1;
01880 
01881   recurse++;
01882 
01883   switch (aType)
01884   {
01885   case QtDebugMsg:
01886   case QtWarningMsg:
01887     kdDebug(5006) << aMsg << endl;
01888     break;
01889 
01890   case QtFatalMsg: // Hm, what about using kdFatal() here?
01891     ungrabPtrKb();
01892     kdDebug(5006) << kapp->caption() << " fatal error "
01893           << aMsg << endl;
01894     KMessageBox::error(0, aMsg);
01895     abort();
01896   }
01897 
01898   recurse--;
01899 }
01900 
01901 
01902 void KMKernel::dumpDeadLetters()
01903 {
01904   if ( shuttingDown() )
01905     return; //All documents should be saved before shutting down is set!
01906 
01907   // make all composer windows autosave their contents
01908   if ( !KMainWindow::memberList )
01909     return;
01910 
01911   for ( QPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it ) {
01912     if ( KMail::Composer * win = ::qt_cast<KMail::Composer*>( it.current() ) ) {
01913       win->autoSaveMessage();
01914       // saving the message has to be finished right here, we are called from a dtor,
01915       // therefore we have no chance to finish this later
01916       // yes, this is ugly and potentially dangerous, but the alternative is losing
01917       // currently composed messages...
01918       while ( win->isComposing() )
01919         qApp->processEvents();
01920     }
01921   }
01922 }
01923 
01924 
01925 
01926 void KMKernel::action(bool mailto, bool check, const QString &to,
01927                       const QString &cc, const QString &bcc,
01928                       const QString &subj, const QString &body,
01929                       const KURL &messageFile,
01930                       const KURL::List &attachURLs,
01931                       const QCStringList &customHeaders)
01932 {
01933   if ( mailto )
01934     openComposer( to, cc, bcc, subj, body, 0, messageFile, attachURLs, customHeaders );
01935   else
01936     openReader( check );
01937 
01938   if ( check )
01939     checkMail();
01940   //Anything else?
01941 }
01942 
01943 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KURL &aURL,
01944   bool overwrite)
01945 {
01946   // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
01947   KIO::Job *job = KIO::put(aURL, -1, overwrite, false);
01948   putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
01949   mPutJobs.insert(job, pd);
01950   connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
01951     SLOT(slotDataReq(KIO::Job*,QByteArray&)));
01952   connect(job, SIGNAL(result(KIO::Job*)),
01953     SLOT(slotResult(KIO::Job*)));
01954 }
01955 
01956 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
01957 {
01958   // send the data in 64 KB chunks
01959   const int MAX_CHUNK_SIZE = 64*1024;
01960   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01961   assert(it != mPutJobs.end());
01962   int remainingBytes = (*it).data.size() - (*it).offset;
01963   if( remainingBytes > MAX_CHUNK_SIZE )
01964   {
01965     // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
01966     data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
01967     (*it).offset += MAX_CHUNK_SIZE;
01968     //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes ("
01969     //                << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
01970   }
01971   else
01972   {
01973     // send the remaining bytes to the receiver (deep copy)
01974     data.duplicate( (*it).data.data() + (*it).offset, remainingBytes );
01975     (*it).data = QByteArray();
01976     (*it).offset = 0;
01977     //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n";
01978   }
01979 }
01980 
01981 void KMKernel::slotResult(KIO::Job *job)
01982 {
01983   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01984   assert(it != mPutJobs.end());
01985   if (job->error())
01986   {
01987     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
01988     {
01989       if (KMessageBox::warningContinueCancel(0,
01990         i18n("File %1 exists.\nDo you want to replace it?")
01991         .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace"))
01992         == KMessageBox::Continue)
01993         byteArrayToRemoteFile((*it).data, (*it).url, true);
01994     }
01995     else job->showErrorDialog();
01996   }
01997   mPutJobs.remove(it);
01998 }
01999 
02000 void KMKernel::slotRequestConfigSync() {
02001   // ### FIXME: delay as promised in the kdoc of this function ;-)
02002   KMKernel::config()->sync();
02003 }
02004 
02005 void KMKernel::slotShowConfigurationDialog()
02006 {
02007   if( !mConfigureDialog ) {
02008     mConfigureDialog = new ConfigureDialog( 0, "configure", false );
02009     connect( mConfigureDialog, SIGNAL( configChanged() ),
02010              this, SLOT( slotConfigChanged() ) );
02011   }
02012 
02013   if( KMKernel::getKMMainWidget() == 0 )
02014   {
02015     // ensure that there is a main widget available
02016     // as parts of the configure dialog (identity) rely on this
02017     // and this slot can be called when there is only a KMComposeWin showing
02018     KMMainWin * win = new KMMainWin;
02019     win->show();
02020   }
02021   if( mConfigureDialog->isHidden() )
02022   {
02023     getKMMainWidget()->headers()->writeConfig();
02024     mConfigureDialog->show();
02025   }
02026   else
02027     mConfigureDialog->raise();
02028 }
02029 
02030 void KMKernel::slotConfigChanged()
02031 {
02032   readConfig();
02033   emit configChanged();
02034 }
02035 
02036 //-------------------------------------------------------------------------------
02037 //static
02038 QString KMKernel::localDataPath()
02039 {
02040   return locateLocal( "data", "kmail/" );
02041 }
02042 
02043 //-------------------------------------------------------------------------------
02044 
02045 bool KMKernel::haveSystemTrayApplet()
02046 {
02047   return !systemTrayApplets.isEmpty();
02048 }
02049 
02050 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet )
02051 {
02052   if ( systemTrayApplets.findIndex( applet ) == -1 ) {
02053     systemTrayApplets.append( applet );
02054     return true;
02055   }
02056   else
02057     return false;
02058 }
02059 
02060 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet )
02061 {
02062   QValueList<const KSystemTray*>::iterator it =
02063     systemTrayApplets.find( applet );
02064   if ( it != systemTrayApplets.end() ) {
02065     systemTrayApplets.remove( it );
02066     return true;
02067   }
02068   else
02069     return false;
02070 }
02071 
02072 void KMKernel::emergencyExit( const QString& reason )
02073 {
02074   QString mesg;
02075   if ( reason.length() == 0 ) {
02076     mesg = i18n("KMail encountered a fatal error and will terminate now");
02077   } else {
02078     mesg = i18n("KMail encountered a fatal error and will "
02079                       "terminate now.\nThe error was:\n%1").arg( reason );
02080   }
02081 
02082   kdWarning() << mesg << endl;
02083   KNotifyClient::userEvent( 0, "<qt>"+mesg+"</qt>", KNotifyClient::Messagebox, KNotifyClient::Error );
02084 
02085   ::exit(1);
02086 }
02087 
02091 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
02092 {
02093   assert( folder );
02094   if ( folder == the_outboxFolder )
02095     return true;
02096   return folderIsDrafts( folder );
02097 }
02098 
02099 bool KMKernel::folderIsDrafts(const KMFolder * folder)
02100 {
02101   assert( folder );
02102   if ( folder == the_draftsFolder )
02103     return true;
02104 
02105   QString idString = folder->idString();
02106   if ( idString.isEmpty() )
02107     return false;
02108 
02109   // search the identities if the folder matches the drafts-folder
02110   const KPIM::IdentityManager *im = identityManager();
02111   for ( KPIM::IdentityManager::ConstIterator it=im->begin(); it != im->end(); ++it )
02112     if ( (*it).drafts() == idString )
02113       return true;
02114   return false;
02115 }
02116 
02117 bool KMKernel::folderIsTemplates( const KMFolder *folder )
02118 {
02119   assert( folder );
02120   if ( folder == the_templatesFolder )
02121     return true;
02122 
02123   QString idString = folder->idString();
02124   if ( idString.isEmpty() )
02125     return false;
02126 
02127   // search the identities if the folder matches the templates-folder
02128   const KPIM::IdentityManager *im = identityManager();
02129   for ( KPIM::IdentityManager::ConstIterator it=im->begin(); it != im->end(); ++it )
02130     if ( (*it).templates() == idString )
02131       return true;
02132   return false;
02133 }
02134 
02135 bool KMKernel::folderIsTrash(KMFolder * folder)
02136 {
02137   assert(folder);
02138   if (folder == the_trashFolder) return true;
02139   QStringList actList = acctMgr()->getAccounts();
02140   QStringList::Iterator it( actList.begin() );
02141   for( ; it != actList.end() ; ++it ) {
02142     KMAccount* act = acctMgr()->findByName( *it );
02143     if ( act && ( act->trash() == folder->idString() ) )
02144       return true;
02145   }
02146   return false;
02147 }
02148 
02149 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
02150 {
02151   assert( folder );
02152   if ( folder == the_sentFolder )
02153     return true;
02154 
02155   QString idString = folder->idString();
02156   if ( idString.isEmpty() ) return false;
02157 
02158   // search the identities if the folder matches the sent-folder
02159   const KPIM::IdentityManager * im = identityManager();
02160   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
02161     if ( (*it).fcc() == idString ) return true;
02162   return false;
02163 }
02164 
02165 KPIM::IdentityManager * KMKernel::identityManager() {
02166   if ( !mIdentityManager ) {
02167     kdDebug(5006) << "instantating KPIM::IdentityManager" << endl;
02168     mIdentityManager = new KPIM::IdentityManager( false, this, "mIdentityManager" );
02169   }
02170   return mIdentityManager;
02171 }
02172 
02173 KMMsgIndex *KMKernel::msgIndex()
02174 {
02175     return the_msgIndex;
02176 }
02177 
02178 KMainWindow* KMKernel::mainWin()
02179 {
02180   if (KMainWindow::memberList) {
02181     KMainWindow *kmWin = 0;
02182 
02183     // First look for a KMMainWin.
02184     for (kmWin = KMainWindow::memberList->first(); kmWin;
02185          kmWin = KMainWindow::memberList->next())
02186       if (kmWin->isA("KMMainWin"))
02187         return kmWin;
02188 
02189     // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
02190     // case we are running inside Kontact) because we anyway only need
02191     // it for modal message boxes and for KNotify events.
02192     kmWin = KMainWindow::memberList->first();
02193     if ( kmWin )
02194       return kmWin;
02195   }
02196 
02197   // There's not a single KMainWindow. Create a KMMainWin.
02198   // This could happen if we want to pop up an error message
02199   // while we are still doing the startup wizard and no other
02200   // KMainWindow is running.
02201   mWin = new KMMainWin;
02202   return mWin;
02203 }
02204 
02205 
02209 void KMKernel::slotEmptyTrash()
02210 {
02211   QString title = i18n("Empty Trash");
02212   QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
02213   if (KMessageBox::warningContinueCancel(0, text, title,
02214                                          KStdGuiItem::cont(), "confirm_empty_trash")
02215       != KMessageBox::Continue)
02216   {
02217     return;
02218   }
02219 
02220   for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
02221   {
02222     KMFolder* trash = findFolderById(acct->trash());
02223     if (trash)
02224     {
02225       trash->expunge();
02226     }
02227   }
02228 }
02229 
02230 KConfig* KMKernel::config()
02231 {
02232   assert(mySelf);
02233   if (!mySelf->mConfig)
02234   {
02235     mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
02236     // Check that all updates have been run on the config file:
02237     KMail::checkConfigUpdates();
02238   }
02239   return mySelf->mConfig;
02240 }
02241 
02242 KMailICalIfaceImpl& KMKernel::iCalIface()
02243 {
02244   assert( mICalIface );
02245   return *mICalIface;
02246 }
02247 
02248 void KMKernel::selectFolder( QString folderPath )
02249 {
02250   kdDebug(5006)<<"Selecting a folder "<<folderPath<<endl;
02251   const QString localPrefix = "/Local";
02252   KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
02253   if ( !folder && folderPath.startsWith( localPrefix ) )
02254     folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
02255   if ( !folder )
02256     folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
02257   if ( !folder )
02258     folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
02259   Q_ASSERT( folder );
02260 
02261   KMMainWidget *widget = getKMMainWidget();
02262   Q_ASSERT( widget );
02263   if ( !widget )
02264     return;
02265 
02266   KMFolderTree *tree = widget->folderTree();
02267   tree->doFolderSelected( tree->indexOfFolder( folder ) );
02268   tree->ensureItemVisible( tree->indexOfFolder( folder ) );
02269 }
02270 
02271 KMMainWidget *KMKernel::getKMMainWidget()
02272 {
02273   //This could definitely use a speadup
02274   QWidgetList *l = kapp->topLevelWidgets();
02275   QWidgetListIt it( *l );
02276   QWidget *wid;
02277 
02278   while ( ( wid = it.current() ) != 0 ) {
02279     ++it;
02280     QObjectList *l2 = wid->topLevelWidget()->queryList( "KMMainWidget" );
02281     if (l2 && l2->first()) {
02282       KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2->first() );
02283       Q_ASSERT( kmmw );
02284       delete l2;
02285       delete l;
02286       return kmmw;
02287     }
02288     delete l2;
02289   }
02290   delete l;
02291   return 0;
02292 }
02293 
02294 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
02295 {
02296   // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
02297   // a stable kmail release goes out with a nasty bug in CompactionJob...
02298   KConfigGroup generalGroup( config(), "General" );
02299 
02300   if ( generalGroup.readBoolEntry( "auto-expiring", true ) ) {
02301     the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02302     the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02303     the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
02304     // the_searchFolderMgr: no expiry there
02305   }
02306 
02307   if ( generalGroup.readBoolEntry( "auto-compaction", true ) ) {
02308     the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
02309     // the_imapFolderMgr: no compaction
02310     the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
02311     // the_searchFolderMgr: no compaction
02312   }
02313 
02314 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
02315   mBackgroundTasksTimer->start( 60 * 1000, true ); // check again in 1 minute
02316 #else
02317   mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours
02318 #endif
02319 
02320 }
02321 
02322 void KMKernel::expireAllFoldersNow() // called by the GUI
02323 {
02324   the_folderMgr->expireAllFolders( true /*immediate*/ );
02325   the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
02326   the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
02327 }
02328 
02329 void KMKernel::compactAllFolders() // called by the GUI
02330 {
02331   the_folderMgr->compactAllFolders( true /*immediate*/ );
02332   //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
02333   the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
02334 }
02335 
02336 KMFolder* KMKernel::findFolderById( const QString& idString )
02337 {
02338   KMFolder * folder = the_folderMgr->findIdString( idString );
02339   if ( !folder )
02340     folder = the_imapFolderMgr->findIdString( idString );
02341   if ( !folder )
02342     folder = the_dimapFolderMgr->findIdString( idString );
02343   if ( !folder )
02344     folder = the_searchFolderMgr->findIdString( idString );
02345   return folder;
02346 }
02347 
02348 ::KIMProxy* KMKernel::imProxy()
02349 {
02350   return KIMProxy::instance( kapp->dcopClient() );
02351 }
02352 
02353 void KMKernel::enableMailCheck()
02354 {
02355   mMailCheckAborted = false;
02356 }
02357 
02358 bool KMKernel::mailCheckAborted() const
02359 {
02360   return mMailCheckAborted;
02361 }
02362 
02363 void KMKernel::abortMailCheck()
02364 {
02365   mMailCheckAborted = true;
02366 }
02367 
02368 bool KMKernel::canQueryClose()
02369 {
02370   if ( KMMainWidget::mainWidgetList() &&
02371        KMMainWidget::mainWidgetList()->count() > 1 )
02372     return true;
02373   KMMainWidget *widget = getKMMainWidget();
02374   if ( !widget )
02375     return true;
02376   KMSystemTray* systray = widget->systray();
02377   if ( !systray || GlobalSettings::closeDespiteSystemTray() )
02378       return true;
02379   if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
02380     systray->hideKMail();
02381     return false;
02382   } else if ( ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) && ( systray->hasUnreadMail() )) {
02383     systray->show();
02384     systray->hideKMail();
02385     return false;
02386   }
02387   return true;
02388 }
02389 
02390 void KMKernel::messageCountChanged()
02391 {
02392   mTimeOfLastMessageCountChange = ::time( 0 );
02393 }
02394 
02395 int KMKernel::timeOfLastMessageCountChange() const
02396 {
02397   return mTimeOfLastMessageCountChange;
02398 }
02399 
02400 Wallet *KMKernel::wallet() {
02401   static bool walletOpenFailed = false;
02402   if ( mWallet && mWallet->isOpen() )
02403     return mWallet;
02404 
02405   if ( !Wallet::isEnabled() || walletOpenFailed )
02406     return 0;
02407 
02408   // find an appropriate parent window for the wallet dialog
02409   WId window = 0;
02410   if ( qApp->activeWindow() )
02411     window = qApp->activeWindow()->winId();
02412   else if ( getKMMainWidget() )
02413     window = getKMMainWidget()->topLevelWidget()->winId();
02414 
02415   delete mWallet;
02416   mWallet = Wallet::openWallet( Wallet::NetworkWallet(), window );
02417 
02418   if ( !mWallet ) {
02419     walletOpenFailed = true;
02420     return 0;
02421   }
02422 
02423   if ( !mWallet->hasFolder( "kmail" ) )
02424     mWallet->createFolder( "kmail" );
02425   mWallet->setFolder( "kmail" );
02426   return mWallet;
02427 }
02428 
02429 QValueList< QGuardedPtr<KMFolder> > KMKernel::allFolders()
02430 {
02431   QStringList names;
02432   QValueList<QGuardedPtr<KMFolder> > folders;
02433   folderMgr()->createFolderList(&names, &folders);
02434   imapFolderMgr()->createFolderList(&names, &folders);
02435   dimapFolderMgr()->createFolderList(&names, &folders);
02436   searchFolderMgr()->createFolderList(&names, &folders);
02437 
02438   return folders;
02439 }
02440 
02441 KMFolder *KMKernel::currentFolder() {
02442   KMMainWidget *widget = getKMMainWidget();
02443   KMFolder *folder = 0;
02444   if ( widget && widget->folderTree() ) {
02445     folder = widget->folderTree()->currentFolder();
02446   }
02447   return folder;
02448 }
02449 
02450 // can't be inline, since KMSender isn't known to implement
02451 // KMail::MessageSender outside this .cpp file
02452 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; }
02453 
02454 #include "kmkernel.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys