kmail

kmkernel.cpp

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