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