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