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