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