kmail

kmkernel.cpp

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