kmail

kmkernel.cpp

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