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