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