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