kmail Library API Documentation

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 "kmstartup.h"
00013 #include "kmmsgindex.h"
00014 #include "kmmainwin.h"
00015 #include "kmcomposewin.h"
00016 #include "kmfoldermgr.h"
00017 #include "kmfoldercachedimap.h"
00018 #include "kmacctcachedimap.h"
00019 #include "kmfiltermgr.h"
00020 #include "kmfilteraction.h"
00021 #include "kmsender.h"
00022 #include "undostack.h"
00023 #include "kmacctmgr.h"
00024 #include "kfileio.h"
00025 #include "kmversion.h"
00026 #include "kmreaderwin.h"
00027 #include "kmmainwidget.h"
00028 #include "recentaddresses.h"
00029 using KRecentAddress::RecentAddresses;
00030 #include "kmmsgdict.h"
00031 #include "kmidentity.h"
00032 #include "identitymanager.h"
00033 #include "configuredialog.h"
00034 // #### disabled for now #include "startupwizard.h"
00035 #include <kwin.h>
00036 #include "kmgroupware.h"
00037 #include "kmailicalifaceimpl.h"
00038 #include "mailserviceimpl.h"
00039 using KMail::MailServiceImpl;
00040 #include "folderIface.h"
00041 using KMail::FolderIface;
00042 #include "cryptplugwrapperlist.h"
00043 
00044 #include <kapplication.h>
00045 #include <kaboutdata.h>
00046 #include <kmessagebox.h>
00047 #include <knotifyclient.h>
00048 #include <kstaticdeleter.h>
00049 #include <kstandarddirs.h>
00050 #include <kconfig.h>
00051 #include <kprogress.h>
00052 #include <kpassivepopup.h>
00053 #include <dcopclient.h>
00054 #include <ksystemtray.h>
00055 
00056 #include <kdebug.h>
00057 
00058 #include <qutf7codec.h>
00059 #include <qvbox.h>
00060 #include <qdir.h>
00061 #include <qobjectlist.h>
00062 
00063 #include <sys/types.h>
00064 #include <dirent.h>
00065 #include <sys/stat.h>
00066 #include <unistd.h>
00067 #include <stdio.h>
00068 #include <stdlib.h>
00069 #include <assert.h>
00070 
00071 #include <X11/Xlib.h>
00072 #include <fixx11h.h>
00073 #include <kcmdlineargs.h>
00074 #include <kstartupinfo.h>
00075 
00076 KMKernel *KMKernel::mySelf = 0;
00077 
00078 /********************************************************************/
00079 /*                     Constructor and destructor                   */
00080 /********************************************************************/
00081 KMKernel::KMKernel (QObject *parent, const char *name) :
00082   DCOPObject("KMailIface"), QObject(parent, name),
00083   mIdentityManager(0), mProgress(0), mConfigureDialog(0),
00084   mContextMenuShown( false )
00085 {
00086   //kdDebug(5006) << "KMKernel::KMKernel" << endl;
00087   mySelf = this;
00088   the_startingUp = true;
00089   closed_by_user = true;
00090   the_firstInstance = true;
00091   the_msgDict = 0;
00092   the_msgIndex = 0;
00093 
00094   the_inboxFolder = 0;
00095   the_outboxFolder = 0;
00096   the_sentFolder = 0;
00097   the_trashFolder = 0;
00098   the_draftsFolder = 0;
00099 
00100   the_folderMgr = 0;
00101   the_imapFolderMgr = 0;
00102   the_dimapFolderMgr = 0;
00103   the_searchFolderMgr = 0;
00104   the_undoStack = 0;
00105   the_acctMgr = 0;
00106   the_filterMgr = 0;
00107   the_popFilterMgr = 0;
00108   the_filterActionDict = 0;
00109   the_msgSender = 0;
00110   mWin = 0;
00111 
00112   mGroupware = new KMGroupware( this );
00113 
00114   // Set up DCOP interface
00115   mICalIface = new KMailICalIfaceImpl();
00116 
00117   mXmlGuiInstance = 0;
00118   mDeadLetterTimer = 0;
00119   mDeadLetterInterval = 1000*120; // 2 minutes
00120   allowedToExpire = false;
00121 
00122   new Kpgp::Module();
00123 
00124   // register our own (libkdenetwork) utf-7 codec as long as Qt
00125   // doesn't have it's own:
00126   if ( !QTextCodec::codecForName("utf-7") ) {
00127     kdDebug(5006) << "No Qt-native utf-7 codec found; registering QUtf7Codec from libkdenetwork" << endl;
00128     (void) new QUtf7Codec();
00129   }
00130 
00131   // In the case of Japan. Japanese locale name is "eucjp" but
00132   // The Japanese mail systems normally used "iso-2022-jp" of locale name.
00133   // We want to change locale name from eucjp to iso-2022-jp at KMail only.
00134   if ( QCString(QTextCodec::codecForLocale()->name()).lower() == "eucjp" )
00135   {
00136     netCodec = QTextCodec::codecForName("jis7");
00137     // QTextCodec *cdc = QTextCodec::codecForName("jis7");
00138     // QTextCodec::setCodecForLocale(cdc);
00139     // KGlobal::locale()->setEncoding(cdc->mibEnum());
00140   } else {
00141     netCodec = QTextCodec::codecForLocale();
00142   }
00143   mMailService =  new MailServiceImpl();
00144 }
00145 
00146 KMKernel::~KMKernel ()
00147 {
00148   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.begin();
00149   while ( it != mPutJobs.end() )
00150   {
00151     KIO::Job *job = it.key();
00152     mPutJobs.remove( it );
00153     job->kill();
00154     it = mPutJobs.begin();
00155   }
00156 
00157   delete mICalIface;
00158   mICalIface = 0L;
00159 
00160   delete mMailService;
00161   mySelf = 0;
00162   kdDebug(5006) << "KMKernel::~KMKernel" << endl;
00163 }
00164 
00165 bool KMKernel::handleCommandLine( bool noArgsOpensReader )
00166 {
00167   QString to, cc, bcc, subj, body;
00168   KURL messageFile;
00169   KURL::List attachURLs;
00170   bool mailto = false;
00171   bool checkMail = false;
00172   //bool viewOnly = false;
00173 
00174   // process args:
00175   KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00176   if (args->getOption("subject"))
00177   {
00178      mailto = true;
00179      subj = QString::fromLocal8Bit(args->getOption("subject"));
00180   }
00181 
00182   if (args->getOption("cc"))
00183   {
00184      mailto = true;
00185      cc = QString::fromLocal8Bit(args->getOption("cc"));
00186   }
00187 
00188   if (args->getOption("bcc"))
00189   {
00190      mailto = true;
00191      bcc = QString::fromLocal8Bit(args->getOption("bcc"));
00192   }
00193 
00194   if (args->getOption("msg"))
00195   {
00196      mailto = true;
00197      messageFile.setPath( QString::fromLocal8Bit(args->getOption("msg")) );
00198   }
00199 
00200   if (args->getOption("body"))
00201   {
00202      mailto = true;
00203      body = QString::fromLocal8Bit(args->getOption("body"));
00204   }
00205 
00206   QCStringList attachList = args->getOptionList("attach");
00207   if (!attachList.isEmpty())
00208   {
00209      mailto = true;
00210      for ( QCStringList::Iterator it = attachList.begin() ; it != attachList.end() ; ++it )
00211        if ( !(*it).isEmpty() )
00212          attachURLs += KURL( QString::fromLocal8Bit( *it ) );
00213   }
00214 
00215   if (args->isSet("composer"))
00216     mailto = true;
00217 
00218   if (args->isSet("check"))
00219     checkMail = true;
00220 
00221   for(int i= 0; i < args->count(); i++)
00222   {
00223     if (strncasecmp(args->arg(i),"mailto:",7)==0)
00224       to += args->url(i).path() + ", ";
00225     else {
00226       QString tmpArg = QString::fromLocal8Bit( args->arg(i) );
00227       KURL url( tmpArg );
00228       if ( url.isValid() )
00229         attachURLs += url;
00230       else
00231         to += tmpArg + ", ";
00232     }
00233     mailto = true;
00234   }
00235   if ( !to.isEmpty() ) {
00236     // cut off the superfluous trailing ", "
00237     to.truncate( to.length() - 2 );
00238   }
00239 
00240   args->clear();
00241 
00242   if (!noArgsOpensReader && !mailto && !checkMail)
00243     return false;
00244 
00245   action (mailto, checkMail, to, cc, bcc, subj, body, messageFile, attachURLs);
00246   return true;
00247 }
00248 
00249 /********************************************************************/
00250 /*             DCOP-callable, and command line actions              */
00251 /********************************************************************/
00252 void KMKernel::checkMail () //might create a new reader but won't show!!
00253 {
00254   kmkernel->acctMgr()->checkMail(false);
00255 }
00256 
00257 QStringList KMKernel::accounts()
00258 {
00259   return kmkernel->acctMgr()->getAccounts();
00260 }
00261 
00262 void KMKernel::checkAccount (const QString &account) //might create a new reader but won't show!!
00263 {
00264   kdDebug(5006) << "KMKernel::checkMail called" << endl;
00265 
00266   KMAccount* acct = kmkernel->acctMgr()->find(account);
00267   if (acct)
00268     kmkernel->acctMgr()->singleCheckMail(acct, false);
00269 }
00270 
00271 void KMKernel::openReader( bool onlyCheck )
00272 {
00273   KMMainWin *mWin = 0;
00274   KMainWindow *ktmw = 0;
00275   kdDebug(5006) << "KMKernel::openReader called" << endl;
00276 
00277   if (KMainWindow::memberList)
00278     for (ktmw = KMainWindow::memberList->first(); ktmw;
00279          ktmw = KMainWindow::memberList->next())
00280       if (ktmw->isA("KMMainWin"))
00281         break;
00282 
00283   bool activate;
00284   if (ktmw) {
00285     mWin = (KMMainWin *) ktmw;
00286     activate = !onlyCheck; // existing window: only activate if not --check
00287   }
00288   else {
00289     mWin = new KMMainWin;
00290     activate = true; // new window: always activate
00291   }
00292 
00293   if ( activate ) {
00294   mWin->show();
00295   // Activate window - doing this instead of KWin::activateWindow(mWin->winId());
00296   // so that it also works when called from KMailApplication::newInstance()
00297 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00298   KStartupInfo::setNewStartupId( mWin, kapp->startupId() );
00299 #endif
00300   }
00301 }
00302 
00303 int KMKernel::openComposer (const QString &to, const QString &cc,
00304                             const QString &bcc, const QString &subject,
00305                             const QString &body, int hidden,
00306                             const KURL &messageFile,
00307                 const KURL::List &attachURLs)
00308 {
00309   kdDebug(5006) << "KMKernel::openComposer called" << endl;
00310 
00311   KMMessage *msg = new KMMessage;
00312   msg->initHeader();
00313   msg->setCharset("utf-8");
00314   if (!cc.isEmpty()) msg->setCc(cc);
00315   if (!bcc.isEmpty()) msg->setBcc(bcc);
00316   if (!subject.isEmpty()) msg->setSubject(subject);
00317   if (!to.isEmpty()) msg->setTo(to);
00318 
00319   if (!messageFile.isEmpty() && messageFile.isLocalFile()) {
00320     QCString str = kFileToString( messageFile.path(), true, false );
00321     if( !str.isEmpty() )
00322       msg->setBody( QString::fromLocal8Bit( str ).utf8() );
00323   }
00324   else if (!body.isEmpty())
00325     msg->setBody(body.utf8());
00326 
00327   KMComposeWin *cWin = new KMComposeWin(msg);
00328   cWin->setCharset("", TRUE);
00329   for ( KURL::List::ConstIterator it = attachURLs.begin() ; it != attachURLs.end() ; ++it )
00330     cWin->addAttach((*it));
00331   if (hidden == 0) {
00332     cWin->show();
00333     // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
00334     // so that it also works when called from KMailApplication::newInstance()
00335 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00336     KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
00337 #endif
00338   }
00339   return 1;
00340 }
00341 
00342 
00343 int KMKernel::openComposer (const QString &to, const QString &cc,
00344                             const QString &bcc, const QString &subject,
00345                             const QString &body, int hidden,
00346                             const QString &attachName,
00347                             const QCString &attachCte,
00348                             const QCString &attachData,
00349                             const QCString &attachType,
00350                             const QCString &attachSubType,
00351                             const QCString &attachParamAttr,
00352                             const QString &attachParamValue,
00353                             const QCString &attachContDisp)
00354 {
00355   kdDebug(5006) << "KMKernel::openComposer called" << endl;
00356 
00357   KMMessage *msg = new KMMessage;
00358   msg->initHeader();
00359   msg->setCharset("utf-8");
00360   if (!cc.isEmpty()) msg->setCc(cc);
00361   if (!bcc.isEmpty()) msg->setBcc(bcc);
00362   if (!subject.isEmpty()) msg->setSubject(subject);
00363   if (!to.isEmpty()) msg->setTo(to);
00364   if (!body.isEmpty()) msg->setBody(body.utf8());
00365 
00366   KMComposeWin *cWin = new KMComposeWin(msg);
00367   cWin->setCharset("", TRUE);
00368   if (!attachData.isEmpty()) {
00369     KMMessagePart *msgPart = new KMMessagePart;
00370     msgPart->setName(attachName);
00371     msgPart->setCteStr(attachCte);
00372     msgPart->setBodyEncoded(attachData);
00373     msgPart->setTypeStr(attachType);
00374     msgPart->setSubtypeStr(attachSubType);
00375     msgPart->setParameter(attachParamAttr,attachParamValue);
00376     msgPart->setContentDisposition(attachContDisp);
00377     cWin->addAttach(msgPart);
00378   }
00379 
00380   if (hidden == 0) {
00381     cWin->show();
00382     // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
00383     // so that it also works when called from KMailApplication::newInstance()
00384 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00385     KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
00386 #endif
00387   }
00388   return 1;
00389 }
00390 
00391 DCOPRef KMKernel::openComposer(const QString &to, const QString &cc,
00392                                const QString &bcc, const QString &subject,
00393                                const QString &body,bool hidden)
00394 {
00395   KMMessage *msg = new KMMessage;
00396   msg->initHeader();
00397   msg->setCharset("utf-8");
00398   if (!cc.isEmpty()) msg->setCc(cc);
00399   if (!bcc.isEmpty()) msg->setBcc(bcc);
00400   if (!subject.isEmpty()) msg->setSubject(subject);
00401   if (!to.isEmpty()) msg->setTo(to);
00402   if (!body.isEmpty()) msg->setBody(body.utf8());
00403 
00404   KMComposeWin *cWin = new KMComposeWin(msg);
00405   cWin->setCharset("", TRUE);
00406   if (!hidden) {
00407     cWin->show();
00408     // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
00409     // so that it also works when called from KMailApplication::newInstance()
00410 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00411     KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
00412 #endif
00413   }
00414 
00415   return DCOPRef(cWin);
00416 }
00417 
00418 int KMKernel::sendCertificate( const QString& to, const QByteArray& certData )
00419 {
00420   KMMessage *msg = new KMMessage;
00421   msg->initHeader();
00422   msg->setCharset("utf-8");
00423   msg->setSubject( i18n( "Certificate Signature Request" ) );
00424   if (!to.isEmpty()) msg->setTo(to);
00425   msg->setBody( i18n( "Please sign this certificate and return to sender." ).utf8() );
00426 
00427   KMComposeWin *cWin = new KMComposeWin(msg);
00428   cWin->setCharset("", TRUE);
00429   cWin->slotSetAlwaysSend( true );
00430   if (!certData.isEmpty()) {
00431     KMMessagePart *msgPart = new KMMessagePart;
00432     msgPart->setName("smime.p10");
00433     msgPart->setCteStr("base64");
00434     msgPart->setBodyEncodedBinary(certData);
00435     msgPart->setTypeStr("application");
00436     msgPart->setSubtypeStr("pkcs10");
00437     msgPart->setContentDisposition("attachment; filename=smime.p10");
00438     cWin->addAttach(msgPart);
00439   }
00440 
00441   cWin->show();
00442   return 1;
00443 }
00444 
00445 
00446 void KMKernel::compactAllFolders ()
00447 {
00448   kdDebug(5006) << "KMKernel::compactAllFolders called" << endl;
00449   the_folderMgr->compactAll();
00450   kdDebug(5006) << "KMKernel::compactAllFolders finished" << endl;
00451 }
00452 
00453 int KMKernel::dcopAddMessage(const QString & foldername,const QString & msgUrlString)
00454 {
00455   return dcopAddMessage(foldername, KURL(msgUrlString));
00456 }
00457 
00458 int KMKernel::dcopAddMessage(const QString & foldername,const KURL & msgUrl)
00459 {
00460   if ( foldername.isEmpty() )
00461     return -1;
00462 
00463   int retval;
00464   QCString messageText;
00465   static QStringList *msgIds = 0;
00466   static QString      lastFolder = "";
00467   bool readFolderMsgIds = false;
00468 
00469   //kdDebug(5006) << "KMKernel::dcopAddMessage called" << endl;
00470 
00471   if ( foldername != lastFolder ) {
00472     if ( msgIds != 0 ) {
00473       delete msgIds;
00474       msgIds = 0;
00475     }
00476     msgIds = new QStringList;
00477     readFolderMsgIds = true;
00478     lastFolder = foldername;
00479   }
00480 
00481   if (!msgUrl.isEmpty() && msgUrl.isLocalFile()) {
00482 
00483     // This is a proposed change by Daniel Andor.
00484     // He proposed to change from the fopen(blah)
00485     // to a kFileToString(blah).
00486     // Although it assigns a QString to a QString,
00487     // because of the implicit sharing this poses
00488     // no memory or performance penalty.
00489 
00490     messageText = kFileToString( msgUrl.path(), true, false);
00491     if ( messageText.isNull() )
00492       return -2;
00493 
00494     KMMessage *msg = new KMMessage();
00495     msg->fromString( messageText );
00496 
00497     KMFolder *folder = the_folderMgr->findOrCreate(foldername, false);
00498 
00499     if ( folder ) {
00500       if (readFolderMsgIds) {
00501 
00502         // Try to determine if a message already exists in
00503         // the folder. The message id that is searched for, is
00504         // the subject line + the date. This should be quite
00505         // unique. The change that a given date with a given
00506         // subject is in the folder twice is very small.
00507 
00508         // If the subject is empty, the fromStrip string
00509         // is taken.
00510         int i;
00511 
00512         folder->open();
00513         for( i=0; i<folder->count(); i++) {
00514           KMMsgBase *mb = folder->getMsgBase(i);
00515           time_t  DT = mb->date();
00516           QString dt = ctime(&DT);
00517           QString id = mb->subject();
00518 
00519           if (id.isEmpty())
00520             id = mb->fromStrip();
00521           if (id.isEmpty())
00522             id = mb->toStrip();
00523 
00524           id+=dt;
00525 
00526           //fprintf(stderr,"%s\n",(const char *) id);
00527           if (!id.isEmpty()) {
00528             msgIds->append(id);
00529           }
00530         }
00531         folder->close();
00532       }
00533 
00534       time_t DT = msg->date();
00535       QString dt = ctime( &DT );
00536       QString msgId = msg->subject();
00537 
00538       if ( msgId.isEmpty() )
00539         msgId = msg->fromStrip();
00540       if ( msgId.isEmpty() )
00541         msgId = msg->toStrip();
00542 
00543       msgId += dt;
00544 
00545       int k = msgIds->findIndex( msgId );
00546       //fprintf(stderr,"find %s = %d\n",(const char *) msgId,k);
00547 
00548       if ( k == -1 ) {
00549         if ( !msgId.isEmpty() ) {
00550           msgIds->append( msgId );
00551         }
00552         if ( folder->addMsg( msg ) == 0 ) {
00553           retval = 1;
00554         } else {
00555           retval =- 2;
00556           delete msg;
00557           msg = 0;
00558         }
00559       } else {
00560         retval = -4;
00561       }
00562     } else {
00563       retval = -1;
00564     }
00565   } else {
00566     retval = -2;
00567   }
00568   return retval;
00569 }
00570 
00571 void KMKernel::requestAddresses( QString filename )
00572 {
00573   mGroupware->requestAddresses( filename );
00574 }
00575 
00576 bool KMKernel::storeAddresses( QString addresses, QStringList delUIDs )
00577 {
00578   return mGroupware->storeAddresses( addresses, delUIDs );
00579 }
00580 
00581 QStringList KMKernel::folderList() const
00582 {
00583   QStringList folders;
00584   the_folderMgr->getFolderURLS( folders );
00585   the_imapFolderMgr->getFolderURLS( folders );
00586   the_dimapFolderMgr->getFolderURLS( folders );
00587   return folders;
00588 }
00589 
00590 DCOPRef KMKernel::getFolder( const QString& vpath )
00591 {
00592   if ( the_folderMgr->getFolderByURL( vpath ) )
00593     return DCOPRef( new FolderIface( vpath ) );
00594   else if ( the_imapFolderMgr->getFolderByURL( vpath ) )
00595     return DCOPRef( new FolderIface( vpath ) );
00596   else if ( the_dimapFolderMgr->getFolderByURL( vpath ) )
00597     return DCOPRef( new FolderIface( vpath ) );
00598   return DCOPRef();
00599 }
00600 
00601 bool KMKernel::showMail( Q_UINT32 serialNumber, QString /* messageId */ )
00602 {
00603   KMMainWidget *mainWidget = 0;
00604   if (KMainWindow::memberList) {
00605     KMainWindow *win = 0;
00606     QObjectList *l;
00607 
00608     // First look for a KMainWindow.
00609     for (win = KMainWindow::memberList->first(); win;
00610          win = KMainWindow::memberList->next()) {
00611       // Then look for a KMMainWidget.
00612       l = win->queryList("KMMainWidget");
00613       if (l && l->first()) {
00614     mainWidget = dynamic_cast<KMMainWidget *>(l->first());
00615     if (win->isActiveWindow())
00616       break;
00617       }
00618     }
00619   }
00620 
00621   if (mainWidget) {
00622     int idx = -1;
00623     KMFolder *folder = 0;
00624     msgDict()->getLocation(serialNumber, &folder, &idx);
00625     if (!folder || (idx == -1))
00626       return false;
00627     folder->open();
00628     KMMsgBase *msgBase = folder->getMsgBase(idx);
00629     if (!msgBase)
00630       return false;
00631     bool unGet = !msgBase->isMessage();
00632     KMMessage *msg = folder->getMsg(idx);
00633     mainWidget->slotSelectFolder(folder);
00634     mainWidget->slotSelectMessage(msg);
00635     if (unGet)
00636       folder->unGetMsg(idx);
00637     folder->close();
00638     return true;
00639   }
00640 
00641   return false;
00642 }
00643 
00644 /********************************************************************/
00645 /*                        Kernel methods                            */
00646 /********************************************************************/
00647 
00648 void KMKernel::quit()
00649 {
00650   // Called when all windows are closed. Will take care of compacting,
00651   // sending... should handle session management too!!
00652 }
00653   /* TODO later:
00654    Asuming that:
00655      - msgsender is nonblocking
00656        (our own, QSocketNotifier based. Pops up errors and sends signal
00657         senderFinished when done)
00658      - compacting is non blocking (insert processEvents there)
00659 
00660    o If we are getting mail, stop it (but donīt lose something!)
00661    o If we are sending mail, go on UNLESS this was called by SM,
00662        in which case stop ASAP that too (can we warn? should we continue
00663        on next start?)
00664    o If we are compacting, or expunging, go on UNLESS this was SM call.
00665        In that case stop compacting ASAP and continue on next start, before
00666        touching any folders.
00667 
00668    KMKernel::quit ()
00669    {
00670      SM call?
00671        if compacting, stop;
00672        if sending, stop;
00673        if receiving, stop;
00674        Windows will take care of themselves (composer should dump
00675         itīs messages, if any but not in deadMail)
00676        declare us ready for the End of the Session
00677 
00678      No, normal quit call
00679        All windows are off. Anything to do, should compact or sender sends?
00680          Yes, maybe put an icon in panel as a sign of life
00681          Folder manager, go compacting (*except* outbox and sent-mail!)
00682          if sender sending, connect us to his finished slot, declare us ready
00683                             for quit and wait for senderFinished
00684          if not, Folder manager, go compact sent-mail and outbox
00685 }                (= call slotFinished())
00686 
00687 void KMKernel::slotSenderFinished()
00688 {
00689   good, Folder manager go compact sent-mail and outbox
00690   clean up stage1 (release folders and config, unregister from dcop)
00691     -- another kmail may start now ---
00692   kapp->quit();
00693 }
00694 
00695 void KMKernel::
00696 void KMKernel::
00697 */
00698 
00699 
00700 /********************************************************************/
00701 /*            Init, Exit, and handler  methods                      */
00702 /********************************************************************/
00703 void KMKernel::testDir(const char *_name)
00704 {
00705   QString foldersPath = QDir::homeDirPath() + QString( _name );
00706   QFileInfo info( foldersPath );
00707   if ( !info.exists() ) {
00708     if ( ::mkdir( QFile::encodeName( foldersPath ) , S_IRWXU ) == -1 ) {
00709       KMessageBox::sorry(0, i18n("KMail couldn't create folder '%1'.\n"
00710                                  "Please make sure that you can view and "
00711                                  "modify the content of the folder '%2'.")
00712                             .arg( foldersPath ).arg( QDir::homeDirPath() ) );
00713       ::exit(-1);
00714     }
00715   }
00716   if ( !info.isDir() || !info.isReadable() || !info.isWritable() ) {
00717     KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
00718                                "incorrect.\n"
00719                                "Please make sure that you can view and modify "
00720                                "the content of this folder.")
00721                           .arg( foldersPath ) );
00722     ::exit(-1);
00723   }
00724 }
00725 
00726 
00727 //-----------------------------------------------------------------------------
00728 // Open a composer for each message found in ~/dead.letter
00729 //to control
00730 void KMKernel::recoverDeadLetters(void)
00731 {
00732   KMComposeWin* win;
00733   KMMessage* msg;
00734   QDir dir = QDir::home();
00735   QString fname = dir.path();
00736   int i, rc, num;
00737   mDeadLetterTimer = new QTimer(this);
00738   connect(mDeadLetterTimer, SIGNAL(timeout()), this, SLOT(dumpDeadLetters()));
00739 
00740   if (!dir.exists("dead.letter")) {
00741       mDeadLetterTimer->start(mDeadLetterInterval);
00742       return;
00743   }
00744 
00745   fname += "/dead.letter";
00746   KMFolderMbox folder(0, fname);
00747 
00748   folder.setAutoCreateIndex(FALSE);
00749   rc = folder.open();
00750   if (rc)
00751   {
00752     perror(QString("cannot open file "+fname).latin1());
00753     mDeadLetterTimer->start(mDeadLetterInterval);
00754     return;
00755   }
00756 
00757   folder.open();
00758 
00759   num = folder.count();
00760   for (i=0; i<num; i++)
00761   {
00762     msg = folder.take(0);
00763     if (msg)
00764     {
00765       win = new KMComposeWin();
00766       win->setMsg(msg, false, false, true);
00767       win->show();
00768     }
00769   }
00770   folder.close();
00771   QFile::remove(fname);
00772   mDeadLetterTimer->start(mDeadLetterInterval);
00773 }
00774 
00775 void KMKernel::initFolders(KConfig* cfg)
00776 {
00777   QString name;
00778 
00779   name = cfg->readEntry("inboxFolder");
00780 
00781   // Currently the folder manager cannot manage folders which are not
00782   // in the base folder directory.
00783   //if (name.isEmpty()) name = getenv("MAIL");
00784 
00785   if (name.isEmpty()) name = I18N_NOOP("inbox");
00786 
00787   the_inboxFolder  = (KMFolder*)the_folderMgr->findOrCreate(name);
00788 
00789   if (the_inboxFolder->canAccess() != 0) {
00790     emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
00791   }
00792 
00793   the_inboxFolder->setSystemFolder(TRUE);
00794   if ( the_inboxFolder->userWhoField().isEmpty() )
00795     the_inboxFolder->setUserWhoField( QString::null );
00796   // inboxFolder->open();
00797 
00798   the_outboxFolder = the_folderMgr->findOrCreate(cfg->readEntry("outboxFolder", I18N_NOOP("outbox")));
00799   if (the_outboxFolder->canAccess() != 0) {
00800     emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
00801   }
00802 
00803   the_outboxFolder->setType("Out");
00804   the_outboxFolder->setSystemFolder(TRUE);
00805   if ( the_outboxFolder->userWhoField().isEmpty() )
00806     the_outboxFolder->setUserWhoField( QString::null );
00807   the_outboxFolder->open();
00808 
00809   the_sentFolder = the_folderMgr->findOrCreate(cfg->readEntry("sentFolder", I18N_NOOP("sent-mail")));
00810   if (the_sentFolder->canAccess() != 0) {
00811     emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
00812   }
00813   the_sentFolder->setType("St");
00814   the_sentFolder->setSystemFolder(TRUE);
00815   if ( the_sentFolder->userWhoField().isEmpty() )
00816     the_sentFolder->setUserWhoField( QString::null );
00817   // the_sentFolder->open();
00818 
00819   the_trashFolder  = the_folderMgr->findOrCreate(cfg->readEntry("trashFolder", I18N_NOOP("trash")));
00820   if (the_trashFolder->canAccess() != 0) {
00821     emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
00822   }
00823   the_trashFolder->setType("Tr");
00824   the_trashFolder->setSystemFolder(TRUE);
00825   if ( the_trashFolder->userWhoField().isEmpty() )
00826     the_trashFolder->setUserWhoField( QString::null );
00827   // the_trashFolder->open();
00828 
00829   the_draftsFolder = the_folderMgr->findOrCreate(cfg->readEntry("draftsFolder", I18N_NOOP("drafts")));
00830   if (the_draftsFolder->canAccess() != 0) {
00831     emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
00832   }
00833   the_draftsFolder->setType("Df");
00834   the_draftsFolder->setSystemFolder(TRUE);
00835   if ( the_draftsFolder->userWhoField().isEmpty() )
00836     the_draftsFolder->setUserWhoField( QString::null );
00837   the_draftsFolder->open();
00838 }
00839 
00840 
00841 void KMKernel::init()
00842 {
00843   QString foldersPath;
00844   KConfig* cfg;
00845 
00846   the_shuttingDown = false;
00847   the_server_is_ready = false;
00848 
00849   cfg = KMKernel::config();
00850 
00851   mCryptPlugList = new CryptPlugWrapperList();
00852   mCryptPlugList->loadFromConfig( cfg );
00853 
00854   QDir dir;
00855   QString d = locateLocal("data", "kmail/");
00856 
00857   KConfigGroupSaver saver(cfg, "General");
00858   the_firstStart = cfg->readBoolEntry("first-start", true);
00859   cfg->writeEntry("first-start", false);
00860   the_previousVersion = cfg->readEntry("previous-version");
00861   cfg->writeEntry("previous-version", KMAIL_VERSION);
00862   foldersPath = cfg->readEntry("folders");
00863 
00864   if (foldersPath.isEmpty())
00865   {
00866     foldersPath = QDir::homeDirPath() + QString("/Mail");
00867     transferMail();
00868   }
00869   the_undoStack     = new UndoStack(20);
00870   the_folderMgr     = new KMFolderMgr(foldersPath);
00871   the_imapFolderMgr = new KMFolderMgr(locateLocal("data","kmail/imap"), KMImapDir);
00872   the_dimapFolderMgr = new KMFolderMgr(locateLocal("data","kmail/dimap"), KMDImapDir);
00873   the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir);
00874   the_acctMgr       = new KMAcctMgr();
00875   the_filterMgr     = new KMFilterMgr();
00876   the_popFilterMgr     = new KMFilterMgr(true);
00877   the_filterActionDict = new KMFilterActionDict;
00878 
00879   // moved up here because KMMessage::stripOffPrefixes is used below -ta
00880   KMMessage::readConfig();
00881   initFolders(cfg);
00882   the_acctMgr->readConfig();
00883   the_filterMgr->readConfig();
00884   the_popFilterMgr->readConfig();
00885   cleanupImapFolders();
00886 
00887   the_msgSender = new KMSender;
00888   the_server_is_ready = true;
00889 
00890   { // area for config group "Composer"
00891     KConfigGroupSaver saver(cfg, "Composer");
00892     if (cfg->readListEntry("pref-charsets").isEmpty())
00893     {
00894       cfg->writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
00895     }
00896   }
00897   mGroupware->readConfig();
00898   mICalIface->readConfig();
00899   // filterMgr->dump();
00900 #if 0 //disabled for now..
00901   the_msgIndex = new KMMsgIndex(this, "the_index"); //create the indexer
00902   the_msgIndex->init();
00903   the_msgIndex->remove();
00904   delete the_msgIndex;
00905   the_msgIndex = 0;
00906 #endif
00907 
00908 #if 0
00909   the_weaver =  new KPIM::ThreadWeaver::Weaver( this );
00910   the_weaverLogger = new KPIM::ThreadWeaver::WeaverThreadLogger(this);
00911   the_weaverLogger->attach (the_weaver);
00912 #endif
00913 
00914 }
00915 
00916 void KMKernel::cleanupImapFolders()
00917 {
00918   KMAccount *acct;
00919   KMFolderNode *node = the_imapFolderMgr->dir().first();
00920   while (node)
00921   {
00922     if (node->isDir() || ((acct = the_acctMgr->find(node->name()))
00923               && ( acct->type() == "imap" )) )
00924     {
00925       node = the_imapFolderMgr->dir().next();
00926     } else {
00927       the_imapFolderMgr->remove(static_cast<KMFolderImap*>(node));
00928       node = the_imapFolderMgr->dir().first();
00929     }
00930   }
00931 
00932   node = the_dimapFolderMgr->dir().first();
00933   while (node)
00934   {
00935     if (node->isDir() || ((acct = the_acctMgr->find(node->name()))
00936               && ( acct->type() == "cachedimap" )) )
00937     {
00938       node = the_dimapFolderMgr->dir().next();
00939     } else {
00940       static_cast<KMFolderCachedImap*>(node)->removeRightAway();
00941       the_dimapFolderMgr->remove(static_cast<KMFolderCachedImap*>(node));
00942       node = the_imapFolderMgr->dir().first();
00943     }
00944   }
00945 
00946   the_imapFolderMgr->quiet(true);
00947   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
00948   {
00949     KMFolderImap *fld;
00950     KMAcctImap *imapAcct;
00951 
00952     if (acct->type() != "imap") continue;
00953     fld = static_cast<KMFolderImap*>(the_imapFolderMgr
00954       ->findOrCreate(acct->name(), false));
00955     fld->setNoContent(true);
00956     imapAcct = static_cast<KMAcctImap*>(acct);
00957     fld->setAccount(imapAcct);
00958     imapAcct->setImapFolder(fld);
00959     fld->close();
00960   }
00961   the_imapFolderMgr->quiet(false);
00962 
00963   the_dimapFolderMgr->quiet( true );
00964   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
00965   {
00966     KMFolderCachedImap *cfld;
00967     KMAcctCachedImap *cachedImapAcct;
00968 
00969     if (acct->type() != "cachedimap" ) continue;
00970 
00971     cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->find(acct->name()));
00972     if (cfld == 0) {
00973       // Folder doesn't exist yet
00974       cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(acct->name(), FALSE, KMFolderTypeCachedImap));
00975       if (!cfld) {
00976     KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_imapFolderMgr->basePath())));
00977     exit(-1);
00978       }
00979     }
00980 
00981     cfld->setNoContent(true);
00982     cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
00983     cfld->setAccount(cachedImapAcct);
00984     cachedImapAcct->setImapFolder(cfld);
00985     cfld->close();
00986   }
00987   the_dimapFolderMgr->quiet( false );
00988 }
00989 
00990 bool KMKernel::doSessionManagement()
00991 {
00992 
00993   // Do session management
00994   if (kapp->isRestored()){
00995     int n = 1;
00996     while (KMMainWin::canBeRestored(n)){
00997       //only restore main windows! (Matthias);
00998       if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
00999         (new KMMainWin)->restore(n);
01000       n++;
01001     }
01002     return true; // we were restored by SM
01003   }
01004   return false;  // no, we were not restored
01005 }
01006 
01007 void KMKernel::closeAllKMTopLevelWidgets()
01008 {
01009   QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01010   KMainWindow *window = 0;
01011   while ((window = it.current()) != 0) {
01012     ++it;
01013     if (window->inherits("KMTopLevelWidget"))
01014       window->close(TRUE);
01015   }
01016 }
01017 
01018 void KMKernel::notClosedByUser()
01019 {
01020   if (!closed_by_user) // already closed
01021     return;
01022   closed_by_user = false;
01023   the_shuttingDown = true;
01024   closeAllKMTopLevelWidgets();
01025 
01026   delete the_acctMgr;
01027   the_acctMgr = 0;
01028   delete the_filterMgr;
01029   the_filterMgr = 0;
01030   delete the_msgSender;
01031   the_msgSender = 0;
01032   delete the_filterActionDict;
01033   the_filterActionDict = 0;
01034   delete the_undoStack;
01035   the_undoStack = 0;
01036   delete the_popFilterMgr;
01037   the_popFilterMgr = 0;
01038 
01039   QStringList strList;
01040   QValueList<QGuardedPtr<KMFolder> > folders;
01041   KMFolder *folder;
01042   the_folderMgr->createFolderList(&strList, &folders);
01043   for (int i = 0; folders.at(i) != folders.end(); i++)
01044   {
01045     folder = *folders.at(i);
01046     if (!folder || folder->isDir()) continue;
01047     folder->close(TRUE);
01048   }
01049   strList.clear();
01050   folders.clear();
01051   the_searchFolderMgr->createFolderList(&strList, &folders);
01052   for (int i = 0; folders.at(i) != folders.end(); i++)
01053   {
01054     folder = *folders.at(i);
01055     if (!folder || folder->isDir()) continue;
01056     folder->close(TRUE);
01057   }
01058   folderMgr()->writeMsgDict(msgDict());
01059   imapFolderMgr()->writeMsgDict(msgDict());
01060   dimapFolderMgr()->writeMsgDict(msgDict());
01061   delete the_msgIndex;
01062   the_msgIndex = 0;
01063   delete the_folderMgr;
01064   the_folderMgr = 0;
01065   delete the_imapFolderMgr;
01066   the_imapFolderMgr = 0;
01067   delete the_dimapFolderMgr;
01068   the_dimapFolderMgr = 0;
01069   delete the_searchFolderMgr;
01070   the_searchFolderMgr = 0;
01071   delete the_msgDict;
01072   the_msgDict = 0;
01073   delete mConfigureDialog;
01074   mConfigureDialog = 0;
01075   delete mWin;
01076   mWin = 0;
01077 }
01078 
01079 void KMKernel::cleanup(void)
01080 {
01081   dumpDeadLetters();
01082   mDeadLetterTimer->stop();
01083   the_shuttingDown = TRUE;
01084   closeAllKMTopLevelWidgets();
01085 
01086   delete the_acctMgr;
01087   the_acctMgr = 0;
01088   delete the_filterMgr;
01089   the_filterMgr = 0;
01090   delete the_msgSender;
01091   the_msgSender = 0;
01092   delete the_filterActionDict;
01093   the_filterActionDict = 0;
01094   delete the_undoStack;
01095   the_undoStack = 0;
01096   delete the_popFilterMgr;
01097   the_popFilterMgr = 0;
01098 
01099 #if 0
01100   delete the_weaver;
01101   the_weaver = 0;
01102 #endif
01103 
01104   // Since the application has already quit we can't use
01105   // kapp->processEvents() because it will return immediately:
01106   // We first have to fire up a new event loop.
01107   // We use the timer to transfer control to the cleanupLoop function
01108   // once the event loop is running.
01109 
01110   // Don't handle DCOP requests from the event loop
01111   kapp->dcopClient()->suspend();
01112 
01113   // Schedule execution of cleanupLoop
01114   QTimer::singleShot(0, this, SLOT(cleanupLoop()));
01115 
01116   // Start new event loop
01117   kapp->enter_loop();
01118 }
01119 
01120 void KMKernel::cleanupProgress()
01121 {
01122   mProgress->advance( 1 );
01123 }
01124 
01125 void KMKernel::cleanupLoop()
01126 {
01127   QStringList cleanupMsgs;
01128   cleanupMsgs << i18n("Cleaning up...")
01129               << i18n("Emptying trash...")
01130               << i18n("Expiring old messages...")
01131               << i18n("Compacting folders...");
01132   enum { CleaningUpMsgNo = 0,
01133          EmptyTrashMsgNo = 1,
01134          ExpiringOldMessagesMsgNo = 2,
01135          CompactingFoldersMsgNo = 3 };
01136   mProgress = 0;
01137   mCleanupLabel = 0;
01138   mCleanupPopup = 0;
01139   int nrFolders = the_folderMgr->folderCount();
01140   if (closed_by_user)
01141   {
01142     mCleanupPopup = new KPassivePopup();
01143     QVBox *box = mCleanupPopup->standardView( kapp->aboutData()->programName(),
01144                                               QString::null, kapp->miniIcon());
01145     mCleanupLabel = new QLabel( cleanupMsgs[CleaningUpMsgNo], box );
01146     // determine the maximal width of the clean up messages
01147     QFontMetrics fm = mCleanupLabel->fontMetrics();
01148     int maxTextWidth = 0;
01149     for( QStringList::ConstIterator it = cleanupMsgs.begin();
01150          it != cleanupMsgs.end();
01151          ++it ) {
01152       int w;
01153       if( maxTextWidth < ( w = fm.width( *it ) ) )
01154         maxTextWidth = w;
01155     }
01156 
01157     mProgress = new KProgress( box, "kmail-cleanupProgress" );
01158     mProgress->setMinimumWidth( maxTextWidth+20 );
01159     mCleanupPopup->setView( box );
01160 
01161     mProgress->setTotalSteps(nrFolders*2+2);
01162     mProgress->setProgress(1);
01163     QApplication::syncX();
01164     mCleanupPopup->adjustSize();
01165     mCleanupPopup->show();
01166     kapp->processEvents();
01167     connect(the_folderMgr, SIGNAL(progress()), this, SLOT(cleanupProgress()));
01168   }
01169 
01170 
01171   KConfig* config =  KMKernel::config();
01172   KConfigGroupSaver saver(config, "General");
01173 
01174   bool expire = false;
01175   // Expire old messages in all folders.
01176   if (closed_by_user) {
01177     if (config->readNumEntry("when-to-expire")==expireAtExit) {
01178       expire = true;
01179 
01180       if (config->readBoolEntry("warn-before-expire", true)) {
01181     expire = canExpire();
01182       }
01183     }
01184   }
01185 
01186   if (!closed_by_user) {
01187       if (the_trashFolder)
01188       the_trashFolder->close();
01189   }
01190   else if (the_trashFolder) {
01191 
01192     the_trashFolder->close(TRUE);
01193 
01194     if (config->readBoolEntry("empty-trash-on-exit", true))
01195     {
01196       if (mCleanupLabel)
01197       {
01198         mCleanupLabel->setText( cleanupMsgs[EmptyTrashMsgNo] );
01199         QApplication::syncX();
01200         kapp->processEvents();
01201       }
01202       if ( the_trashFolder->count( true ) > 0 )
01203         the_trashFolder->expunge();
01204     }
01205   }
01206 
01207   if (mProgress)
01208     mProgress->setProgress(2);
01209 
01210   if (expire) {
01211     if (mCleanupLabel)
01212     {
01213        mCleanupLabel->setText( cleanupMsgs[ExpiringOldMessagesMsgNo] );
01214        QApplication::syncX();
01215        kapp->processEvents();
01216     }
01217     the_folderMgr->expireAllFolders(0);
01218   }
01219 
01220   if (mProgress)
01221      mProgress->setProgress(2+nrFolders);
01222 
01223   if (closed_by_user && the_folderMgr) {
01224     if (config->readBoolEntry("compact-all-on-exit", true))
01225     {
01226       if (mCleanupLabel)
01227       {
01228         mCleanupLabel->setText( cleanupMsgs[CompactingFoldersMsgNo] );
01229         QApplication::syncX();
01230         kapp->processEvents();
01231       }
01232       the_folderMgr->compactAll(); // I can compact for ages in peace now!
01233     }
01234   }
01235   if (mProgress) {
01236     mCleanupLabel->setText( cleanupMsgs[CleaningUpMsgNo] );
01237     mProgress->setProgress(2+2*nrFolders);
01238     QApplication::syncX();
01239     kapp->processEvents();
01240   }
01241 
01242   if (the_inboxFolder) the_inboxFolder->close(TRUE);
01243   if (the_outboxFolder) the_outboxFolder->close(TRUE);
01244   if (the_sentFolder) the_sentFolder->close(TRUE);
01245   if (the_draftsFolder) the_draftsFolder->close(TRUE);
01246 
01247   mICalIface->cleanup();
01248 
01249   folderMgr()->writeMsgDict(msgDict());
01250   imapFolderMgr()->writeMsgDict(msgDict());
01251   dimapFolderMgr()->writeMsgDict(msgDict());
01252   QValueList<QGuardedPtr<KMFolder> > folders;
01253   QStringList strList;
01254   KMFolder *folder;
01255   the_searchFolderMgr->createFolderList(&strList, &folders);
01256   for (int i = 0; folders.at(i) != folders.end(); i++)
01257   {
01258     folder = *folders.at(i);
01259     if (!folder || folder->isDir()) continue;
01260     folder->close(TRUE);
01261   }
01262   delete the_msgIndex;
01263   the_msgIndex = 0;
01264   delete the_folderMgr;
01265   the_folderMgr = 0;
01266   delete the_imapFolderMgr;
01267   the_imapFolderMgr = 0;
01268   delete the_dimapFolderMgr;
01269   the_dimapFolderMgr = 0;
01270   delete the_searchFolderMgr;
01271   the_searchFolderMgr = 0;
01272   delete the_msgDict;
01273   the_msgDict = 0;
01274   delete mConfigureDialog;
01275   mConfigureDialog = 0;
01276   delete mWin;
01277   mWin = 0;
01278   mCryptPlugList->setAutoDelete(true);
01279   mCryptPlugList->clear();
01280   delete mCryptPlugList;
01281   mCryptPlugList = 0;
01282 
01283   //qInstallMsgHandler(oldMsgHandler);
01284   RecentAddresses::self(KMKernel::config())->save( KMKernel::config() );
01285   KMKernel::config()->sync();
01286   if (mCleanupPopup)
01287   {
01288     sleep(1); // Give the user some time to realize what's going on
01289     delete mCleanupPopup;
01290     mCleanupPopup = 0;
01291     mCleanupLabel = 0; // auto-deleted child of mCleanupPopup
01292     mProgress = 0;     // ditto
01293   }
01294   kapp->exit_loop();
01295 }
01296 
01297 //Isnīt this obsolete? (sven)
01298 void KMKernel::transferMail(void)
01299 {
01300   QDir dir = QDir::home();
01301   int rc;
01302 
01303   // Stefan: This function is for all the whiners who think that KMail is
01304   // broken because they cannot read mail with pine and do not
01305   // know how to fix this problem with a simple symbolic link  =;-)
01306   // Markus: lol ;-)
01307   if (!dir.cd("KMail")) return;
01308 
01309   rc = KMessageBox::questionYesNo(0,
01310          i18n(
01311         "The directory ~/KMail exists. From now on, KMail uses the "
01312         "directory ~/Mail for its messages.\n"
01313         "KMail can move the contents of the directory ~/KMail into "
01314         "~/Mail, but this will replace existing files with the same "
01315         "name in the directory ~/Mail (e.g. inbox).\n"
01316         "Should KMail move the mail folders now?"));
01317 
01318   if (rc == KMessageBox::No) return;
01319 
01320   dir.cd("/");  // otherwise we lock the directory
01321   testDir("/Mail");
01322   system("mv -f ~/KMail/* ~/Mail");
01323   system("mv -f ~/KMail/.??* ~/Mail");
01324   system("rmdir ~/KMail");
01325 }
01326 
01327 
01328 void KMKernel::ungrabPtrKb(void)
01329 {
01330   if(!KMainWindow::memberList) return;
01331   QWidget* widg = KMainWindow::memberList->first();
01332   Display* dpy;
01333 
01334   if (!widg) return;
01335   dpy = widg->x11Display();
01336   XUngrabKeyboard(dpy, CurrentTime);
01337   XUngrabPointer(dpy, CurrentTime);
01338 }
01339 
01340 
01341 // Message handler
01342 void KMKernel::kmailMsgHandler(QtMsgType aType, const char* aMsg)
01343 {
01344   static int recurse=-1;
01345 
01346   recurse++;
01347 
01348   switch (aType)
01349   {
01350   case QtDebugMsg:
01351   case QtWarningMsg:
01352     kdDebug(5006) << aMsg << endl;
01353     break;
01354 
01355   case QtFatalMsg: // Hm, what about using kdFatal() here?
01356     ungrabPtrKb();
01357     kdDebug(5006) << kapp->caption() << " fatal error "
01358           << aMsg << endl;
01359     KMessageBox::error(0, aMsg);
01360     abort();
01361   }
01362 
01363   recurse--;
01364 }
01365 void KMKernel::dumpDeadLetters()
01366 {
01367   if (shuttingDown())
01368     return; //All documents should be saved before shutting down is set!
01369   mDeadLetterTimer->stop();
01370   QWidget *win;
01371   QDir dir = QDir::home();
01372   QString fname = dir.path();
01373   QFile::remove(fname + "/dead.letter.tmp");
01374   if (KMainWindow::memberList) {
01375     QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01376 
01377     while ((win = it.current()) != 0) {
01378       ++it;
01379       if (win->inherits("KMComposeWin")) ((KMComposeWin*)win)->deadLetter();
01380       //    delete win; // WABA: Don't delete, we might crash in there!
01381     }
01382   }
01383   QFile::remove(fname + "/dead.letter");
01384   dir.rename("dead.letter.tmp","dead.letter");
01385   mDeadLetterTimer->start(mDeadLetterInterval);
01386 }
01387 
01388 
01389 
01390 void KMKernel::action(bool mailto, bool check, const QString &to,
01391                       const QString &cc, const QString &bcc,
01392                       const QString &subj, const QString &body,
01393                       const KURL &messageFile,
01394                       const KURL::List &attachURLs)
01395 {
01396   // Run the groupware setup wizard. It doesn't do anything if this isn't
01397   // the first run. Replace this with a general wizard later
01398   // #### Disabled until we have a general startup wizard.
01399   // StartupWizard::run();
01400 
01401   if (mailto)
01402     openComposer (to, cc, bcc, subj, body, 0, messageFile, attachURLs);
01403   else
01404     openReader( check );
01405 
01406   if (check)
01407     checkMail();
01408   //Anything else?
01409 }
01410 
01411 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KURL &aURL,
01412   bool overwrite)
01413 {
01414   KIO::Job *job = KIO::put(aURL, -1, overwrite, FALSE);
01415   putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
01416   mPutJobs.insert(job, pd);
01417   connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
01418     SLOT(slotDataReq(KIO::Job*,QByteArray&)));
01419   connect(job, SIGNAL(result(KIO::Job*)),
01420     SLOT(slotResult(KIO::Job*)));
01421 }
01422 
01423 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
01424 {
01425   // send the data in 64 KB chunks
01426   const int MAX_CHUNK_SIZE = 64*1024;
01427   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01428   assert(it != mPutJobs.end());
01429   int remainingBytes = (*it).data.size() - (*it).offset;
01430   if( remainingBytes > MAX_CHUNK_SIZE )
01431   {
01432     // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
01433     data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
01434     (*it).offset += MAX_CHUNK_SIZE;
01435     //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes ("
01436     //                << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
01437   }
01438   else
01439   {
01440     // send the remaining bytes to the receiver (deep copy)
01441     data.duplicate( (*it).data.data() + (*it).offset, remainingBytes );
01442     (*it).data = QByteArray();
01443     (*it).offset = 0;
01444     //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n";
01445   }
01446 }
01447 
01448 void KMKernel::slotResult(KIO::Job *job)
01449 {
01450   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01451   assert(it != mPutJobs.end());
01452   if (job->error())
01453   {
01454     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
01455     {
01456       if (KMessageBox::warningContinueCancel(0,
01457         i18n("File %1 exists.\nDo you want to replace it?")
01458         .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace"))
01459         == KMessageBox::Continue)
01460         byteArrayToRemoteFile((*it).data, (*it).url, TRUE);
01461     }
01462     else job->showErrorDialog();
01463   }
01464   mPutJobs.remove(it);
01465 }
01466 
01467 void KMKernel::slotCollectStdOut( KProcess * proc, char * buffer, int len )
01468 {
01469   QByteArray & ba = mStdOutCollection[proc];
01470   // append data to ba:
01471   int oldsize = ba.size();
01472   ba.resize( oldsize + len );
01473   qmemmove( ba.begin() + oldsize, buffer, len );
01474 }
01475 
01476 void KMKernel::slotCollectStdErr( KProcess * proc, char * buffer, int len )
01477 {
01478   QByteArray & ba = mStdErrCollection[proc];
01479   // append data to ba:
01480   int oldsize = ba.size();
01481   ba.resize( oldsize + len );
01482   qmemmove( ba.begin() + oldsize, buffer, len );
01483 }
01484 
01485 QByteArray KMKernel::getCollectedStdOut( KProcess * proc )
01486 {
01487   QByteArray result = mStdOutCollection[proc];
01488   mStdOutCollection.remove(proc);
01489   return result;
01490 }
01491 
01492 QByteArray KMKernel::getCollectedStdErr( KProcess * proc )
01493 {
01494   QByteArray result = mStdErrCollection[proc];
01495   mStdErrCollection.remove(proc);
01496   return result;
01497 }
01498 
01499 void KMKernel::slotRequestConfigSync() {
01500   // ### FIXME: delay as promised in the kdoc of this function ;-)
01501   KMKernel::config()->sync();
01502 }
01503 
01504 void KMKernel::slotShowConfigurationDialog()
01505 {
01506   if( !mConfigureDialog ) {
01507     mConfigureDialog = new ConfigureDialog( 0, "configure", false );
01508     connect( mConfigureDialog, SIGNAL( configChanged() ),
01509              this, SIGNAL( configChanged() ) );
01510   }
01511 
01512   if( mConfigureDialog->isHidden() )
01513     mConfigureDialog->show();
01514   else
01515     mConfigureDialog->raise();
01516 }
01517 
01518 bool KMKernel::haveSystemTrayApplet()
01519 {
01520   return !systemTrayApplets.isEmpty();
01521 }
01522 
01523 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet )
01524 {
01525   if ( systemTrayApplets.findIndex( applet ) == -1 ) {
01526     systemTrayApplets.append( applet );
01527     return true;
01528   }
01529   else
01530     return false;
01531 }
01532 
01533 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet )
01534 {
01535   QValueList<const KSystemTray*>::iterator it =
01536     systemTrayApplets.find( applet );
01537   if ( it != systemTrayApplets.end() ) {
01538     systemTrayApplets.remove( it );
01539     return true;
01540   }
01541   else
01542     return false;
01543 }
01544 
01545 void KMKernel::emergencyExit( const QString& reason )
01546 {
01547   QString mesg;
01548   if ( reason.length() == 0 ) {
01549     mesg = i18n("KMail encountered a fatal error and will terminate now");
01550   }
01551   else {
01552     mesg = i18n("KMail encountered a fatal error and will "
01553                       "terminate now.\nThe error was:\n%1").arg( reason );
01554   }
01555 
01556   kdWarning() << mesg << endl;
01557   KNotifyClient::userEvent( 0, mesg, KNotifyClient::Messagebox, KNotifyClient::Error );
01558 
01559   ::exit(1);
01560 }
01561 
01569 void
01570 KMKernel::setCanExpire(bool expire) {
01571   allowedToExpire = expire;
01572 }
01573 
01578 bool
01579 KMKernel::canExpire() {
01580   return allowedToExpire;
01581 }
01582 
01586 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
01587 {
01588   assert( folder );
01589   if ( folder == the_outboxFolder || folder == the_draftsFolder )
01590     return true;
01591 
01592   QString idString = folder->idString();
01593   if ( idString.isEmpty() ) return false;
01594 
01595   // search the identities if the folder matches the drafts-folder
01596   const IdentityManager * im = identityManager();
01597   for( IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
01598     if ( (*it).drafts() == idString ) return true;
01599   return false;
01600 }
01601 
01602 bool KMKernel::folderIsTrash(KMFolder * folder)
01603 {
01604   assert(folder);
01605   if (folder == the_trashFolder) return true;
01606   if (folder->folderType() != KMFolderTypeImap) return false;
01607   KMFolderImap *fi = static_cast<KMFolderImap*>(folder);
01608   if (fi->account() && fi->account()->trash() == fi->idString())
01609     return true;
01610   return false;
01611 }
01612 
01613 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
01614 {
01615   assert( folder );
01616   if ( folder == the_sentFolder )
01617     return true;
01618 
01619   QString idString = folder->idString();
01620   if ( idString.isEmpty() ) return false;
01621 
01622   // search the identities if the folder matches the sent-folder
01623   const IdentityManager * im = identityManager();
01624   for( IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
01625     if ( (*it).fcc() == idString ) return true;
01626   return false;
01627 }
01628 
01629 IdentityManager * KMKernel::identityManager() {
01630   if ( !mIdentityManager ) {
01631     kdDebug(5006) << "instantating IdentityManager" << endl;
01632     mIdentityManager = new IdentityManager( this, "mIdentityManager" );
01633   }
01634   return mIdentityManager;
01635 }
01636 
01637 KMMsgDict *KMKernel::msgDict()
01638 {
01639     if (the_msgDict)
01640     return the_msgDict;
01641     the_msgDict = new KMMsgDict;
01642     folderMgr()->readMsgDict(msgDict());
01643     imapFolderMgr()->readMsgDict(msgDict());
01644     dimapFolderMgr()->readMsgDict(msgDict());
01645     return the_msgDict;
01646 }
01647 
01648 KMMsgIndex *KMKernel::msgIndex()
01649 {
01650     return the_msgIndex;
01651 }
01652 
01653 KMainWindow* KMKernel::mainWin()
01654 {
01655   if (KMainWindow::memberList) {
01656     KMainWindow *kmWin = 0;
01657 
01658     // First look for a KMMainWin.
01659     for (kmWin = KMainWindow::memberList->first(); kmWin;
01660          kmWin = KMainWindow::memberList->next())
01661       if (kmWin->isA("KMMainWin"))
01662         return kmWin;
01663 
01664     // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
01665     // case we are running inside Kontact) because we anyway only need
01666     // it for modal message boxes and for KNotify events.
01667     kmWin = KMainWindow::memberList->first();
01668     if ( kmWin )
01669       return kmWin;
01670   }
01671 
01672   // There's not a single KMainWindow. Create a KMMainWin.
01673   // This could happen if we want to pop up an error message
01674   // while we are still doing the startup wizard and no other
01675   // KMainWindow is running.
01676   mWin = new KMMainWin;
01677   return mWin;
01678 }
01679 
01680 
01684 void KMKernel::slotEmptyTrash()
01685 {
01686   QString title = i18n("Empty Trash");
01687   QString text = i18n("Are you sure you want to empty the trash?");
01688   if (KMessageBox::warningContinueCancel(0, text, title,
01689                                          KStdGuiItem::cont(), "confirm_empty_trash")
01690       != KMessageBox::Continue)
01691   {
01692     return;
01693   }
01694 
01695   for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
01696   {
01697     KMFolder* trash = folderMgr()->findIdString(acct->trash());
01698     if (trash)
01699     {
01700       trash->expunge();
01701     }
01702   }
01703 }
01704 
01705 #if KDE_IS_VERSION( 3, 1, 92 )
01706 KConfig* KMKernel::config()
01707 {
01708   assert(mySelf);
01709   if (!mySelf->mConfig)
01710   {
01711     mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
01712     // Check that all updates have been run on the config file:
01713     KMail::checkConfigUpdates();
01714   }
01715   return mySelf->mConfig;
01716 }
01717 #else
01718 KConfig *KMKernel::myConfig = 0;
01719 static KStaticDeleter<KConfig> myConfigSD;
01720 
01721 KConfig* KMKernel::config()
01722 {
01723   if (!myConfig)
01724     myConfig = myConfigSD.setObject(myConfig, new KConfig( "kmailrc"));
01725   return myConfig;
01726 }
01727 #endif
01728 
01729 KMGroupware & KMKernel::groupware()
01730 {
01731   assert( mGroupware );
01732   return *mGroupware;
01733 }
01734 
01735 KMailICalIfaceImpl& KMKernel::iCalIface()
01736 {
01737   assert( mICalIface );
01738   return *mICalIface;
01739 }
01740 
01741 
01742 #include "kmkernel.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:29 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003