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