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)
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   if (name.isEmpty()) name = I18N_NOOP("inbox");
00918 
00919   the_inboxFolder  = (KMFolder*)the_folderMgr->findOrCreate(name);
00920 
00921   if (the_inboxFolder->canAccess() != 0) {
00922     emergencyExit( i18n("You do not have read/write permission to your inbox folder.") );
00923   }
00924 
00925   the_inboxFolder->setSystemFolder(TRUE);
00926   if ( the_inboxFolder->userWhoField().isEmpty() )
00927     the_inboxFolder->setUserWhoField( QString::null );
00928   // inboxFolder->open();
00929 
00930   the_outboxFolder = the_folderMgr->findOrCreate(cfg->readEntry("outboxFolder", I18N_NOOP("outbox")));
00931   if (the_outboxFolder->canAccess() != 0) {
00932     emergencyExit( i18n("You do not have read/write permission to your outbox folder.") );
00933   }
00934   the_outboxFolder->setNoChildren(true);
00935 
00936   the_outboxFolder->setType("Out");
00937   the_outboxFolder->setSystemFolder(TRUE);
00938   if ( the_outboxFolder->userWhoField().isEmpty() )
00939     the_outboxFolder->setUserWhoField( QString::null );
00940   /* Nuke the oubox's index file, to make sure that no ghost messages are in
00941    * it from a previous crash. Ghost messages happen in the outbox because it
00942    * the only folder where messages enter and leave within 5 seconds, which is
00943    * the leniency period for index invalidation. Since the number of mails in
00944    * this folder is expected to be very small, we can live with regenerating
00945    * the index on each start to be on the save side. */
00946   //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir )
00947   //  unlink( QFile::encodeName( the_outboxFolder->indexLocation() ) );
00948   the_outboxFolder->open();
00949 
00950   the_sentFolder = the_folderMgr->findOrCreate(cfg->readEntry("sentFolder", I18N_NOOP("sent-mail")));
00951   if (the_sentFolder->canAccess() != 0) {
00952     emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") );
00953   }
00954   the_sentFolder->setType("St");
00955   the_sentFolder->setSystemFolder(TRUE);
00956   if ( the_sentFolder->userWhoField().isEmpty() )
00957     the_sentFolder->setUserWhoField( QString::null );
00958   // the_sentFolder->open();
00959 
00960   the_trashFolder  = the_folderMgr->findOrCreate(cfg->readEntry("trashFolder", I18N_NOOP("trash")));
00961   if (the_trashFolder->canAccess() != 0) {
00962     emergencyExit( i18n("You do not have read/write permission to your trash folder.") );
00963   }
00964   the_trashFolder->setType("Tr");
00965   the_trashFolder->setSystemFolder(TRUE);
00966   if ( the_trashFolder->userWhoField().isEmpty() )
00967     the_trashFolder->setUserWhoField( QString::null );
00968   // the_trashFolder->open();
00969 
00970   the_draftsFolder = the_folderMgr->findOrCreate(cfg->readEntry("draftsFolder", I18N_NOOP("drafts")));
00971   if (the_draftsFolder->canAccess() != 0) {
00972     emergencyExit( i18n("You do not have read/write permission to your drafts folder.") );
00973   }
00974   the_draftsFolder->setType("Df");
00975   the_draftsFolder->setSystemFolder(TRUE);
00976   if ( the_draftsFolder->userWhoField().isEmpty() )
00977     the_draftsFolder->setUserWhoField( QString::null );
00978   the_draftsFolder->open();
00979 }
00980 
00981 
00982 void KMKernel::init()
00983 {
00984   QString foldersPath;
00985   KConfig* cfg;
00986 
00987   the_shuttingDown = false;
00988   the_server_is_ready = false;
00989 
00990   cfg = KMKernel::config();
00991 
00992   QDir dir;
00993   QString d = locateLocal("data", "kmail/");
00994 
00995   KConfigGroupSaver saver(cfg, "General");
00996   the_firstStart = cfg->readBoolEntry("first-start", true);
00997   cfg->writeEntry("first-start", false);
00998   the_previousVersion = cfg->readEntry("previous-version");
00999   cfg->writeEntry("previous-version", KMAIL_VERSION);
01000   foldersPath = cfg->readEntry("folders");
01001 
01002   if (foldersPath.isEmpty())
01003   {
01004     foldersPath = QDir::homeDirPath() + QString("/Mail");
01005     transferMail();
01006   }
01007   the_undoStack     = new UndoStack(20);
01008   the_folderMgr     = new KMFolderMgr(foldersPath);
01009   the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
01010   the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
01011 
01012   the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir);
01013   KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
01014   if (lsf)
01015     the_searchFolderMgr->remove( lsf );
01016 
01017   the_acctMgr       = new KMAcctMgr();
01018   the_filterMgr     = new KMFilterMgr();
01019   the_popFilterMgr     = new KMFilterMgr(true);
01020   the_filterActionDict = new KMFilterActionDict;
01021 
01022   // moved up here because KMMessage::stripOffPrefixes is used below -ta
01023   KMMessage::readConfig();
01024   initFolders(cfg);
01025   the_acctMgr->readConfig();
01026   the_filterMgr->readConfig();
01027   the_popFilterMgr->readConfig();
01028   cleanupImapFolders();
01029 
01030   the_msgSender = new KMSender;
01031   the_server_is_ready = true;
01032 
01033   { // area for config group "Composer"
01034     KConfigGroupSaver saver(cfg, "Composer");
01035     if (cfg->readListEntry("pref-charsets").isEmpty())
01036     {
01037       cfg->writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8");
01038     }
01039   }
01040   readConfig();
01041   mICalIface->readConfig();
01042   // filterMgr->dump();
01043 #if 0 //disabled for now..
01044   the_msgIndex = new KMMsgIndex(this, "the_index"); //create the indexer
01045   the_msgIndex->init();
01046   the_msgIndex->remove();
01047   delete the_msgIndex;
01048   the_msgIndex = 0;
01049 #endif
01050 
01051 #if 0
01052   the_weaver =  new KPIM::ThreadWeaver::Weaver( this );
01053   the_weaverLogger = new KPIM::ThreadWeaver::WeaverThreadLogger(this);
01054   the_weaverLogger->attach (the_weaver);
01055 #endif
01056 
01057   connect( the_folderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01058            this, SIGNAL( folderRemoved(KMFolder*) ) );
01059   connect( the_dimapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01060            this, SIGNAL( folderRemoved(KMFolder*) ) );
01061   connect( the_imapFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01062            this, SIGNAL( folderRemoved(KMFolder*) ) );
01063   connect( the_searchFolderMgr, SIGNAL( folderRemoved(KMFolder*) ),
01064            this, SIGNAL( folderRemoved(KMFolder*) ) );
01065 
01066   mBackgroundTasksTimer = new QTimer( this );
01067   connect( mBackgroundTasksTimer, SIGNAL( timeout() ), this, SLOT( slotRunBackgroundTasks() ) );
01068 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
01069   mBackgroundTasksTimer->start( 10000, true ); // 10s minute, singleshot
01070 #else
01071   mBackgroundTasksTimer->start( 5 * 60000, true ); // 5 minutes, singleshot
01072 #endif
01073 }
01074 
01075 void KMKernel::readConfig()
01076 {
01077   KConfigGroup composer( config(), "Composer" );
01078   // default to 2 minutes, convert to ms
01079   mDeadLetterInterval = 1000 * 60 * composer.readNumEntry( "autosave", 2 );
01080   kdDebug() << k_funcinfo << mDeadLetterInterval << endl;
01081   if ( mDeadLetterInterval )
01082     mDeadLetterTimer->start( mDeadLetterInterval );
01083   else
01084     mDeadLetterTimer->stop();
01085 }
01086 
01087 void KMKernel::cleanupImapFolders()
01088 {
01089   KMAccount *acct;
01090   KMFolderNode *node = the_imapFolderMgr->dir().first();
01091   while (node)
01092   {
01093     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01094               && ( acct->type() == "imap" )) )
01095     {
01096       node = the_imapFolderMgr->dir().next();
01097     } else {
01098       the_imapFolderMgr->remove(static_cast<KMFolder*>(node));
01099       node = the_imapFolderMgr->dir().first();
01100     }
01101   }
01102 
01103   node = the_dimapFolderMgr->dir().first();
01104   while (node)
01105   {
01106     if (node->isDir() || ((acct = the_acctMgr->find(node->id()))
01107               && ( acct->type() == "cachedimap" )) )
01108     {
01109       node = the_dimapFolderMgr->dir().next();
01110     } else {
01111       the_dimapFolderMgr->remove(static_cast<KMFolder*>(node));
01112       node = the_dimapFolderMgr->dir().first();
01113     }
01114   }
01115 
01116   the_imapFolderMgr->quiet(true);
01117   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01118   {
01119     KMFolderImap *fld;
01120     KMAcctImap *imapAcct;
01121 
01122     if (acct->type() != "imap") continue;
01123     fld = static_cast<KMFolderImap*>(the_imapFolderMgr
01124       ->findOrCreate(QString::number(acct->id()), false, acct->id())->storage());
01125     fld->setNoContent(true);
01126     fld->folder()->setLabel(acct->name());
01127     imapAcct = static_cast<KMAcctImap*>(acct);
01128     fld->setAccount(imapAcct);
01129     imapAcct->setImapFolder(fld);
01130     fld->close();
01131   }
01132   the_imapFolderMgr->quiet(false);
01133 
01134   the_dimapFolderMgr->quiet( true );
01135   for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next())
01136   {
01137     KMFolderCachedImap *cfld = 0;
01138     KMAcctCachedImap *cachedImapAcct;
01139 
01140     if (acct->type() != "cachedimap" ) continue;
01141 
01142     KMFolder* fld = the_dimapFolderMgr->find(QString::number(acct->id()));
01143     if( fld )
01144       cfld = static_cast<KMFolderCachedImap*>( fld->storage() );
01145     if (cfld == 0) {
01146       // Folder doesn't exist yet
01147       cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(QString::number(acct->id()),
01148             false, KMFolderTypeCachedImap)->storage());
01149       if (!cfld) {
01150         KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_dimapFolderMgr->basePath())));
01151         exit(-1);
01152       }
01153       cfld->folder()->setId( acct->id() );
01154     }
01155 
01156     cfld->setNoContent(true);
01157     cfld->folder()->setLabel(acct->name());
01158     cachedImapAcct = static_cast<KMAcctCachedImap*>(acct);
01159     cfld->setAccount(cachedImapAcct);
01160     cachedImapAcct->setImapFolder(cfld);
01161     cfld->close();
01162   }
01163   the_dimapFolderMgr->quiet( false );
01164 }
01165 
01166 bool KMKernel::doSessionManagement()
01167 {
01168 
01169   // Do session management
01170   if (kapp->isRestored()){
01171     int n = 1;
01172     while (KMMainWin::canBeRestored(n)){
01173       //only restore main windows! (Matthias);
01174       if (KMMainWin::classNameOfToplevel(n) == "KMMainWin")
01175         (new KMMainWin)->restore(n);
01176       n++;
01177     }
01178     return true; // we were restored by SM
01179   }
01180   return false;  // no, we were not restored
01181 }
01182 
01183 void KMKernel::closeAllKMailWindows()
01184 {
01185   QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01186   KMainWindow *window = 0;
01187   while ((window = it.current()) != 0) {
01188     ++it;
01189     if (window->isA("KMMainWindow") ||
01190     window->inherits("KMail::SecondaryWindow"))
01191       window->close( true ); // close and delete the window
01192   }
01193 }
01194 
01195 void KMKernel::cleanup(void)
01196 {
01197   dumpDeadLetters();
01198   mDeadLetterTimer->stop();
01199   the_shuttingDown = true;
01200   closeAllKMailWindows();
01201 
01202   delete the_acctMgr;
01203   the_acctMgr = 0;
01204   delete the_filterMgr;
01205   the_filterMgr = 0;
01206   delete the_msgSender;
01207   the_msgSender = 0;
01208   delete the_filterActionDict;
01209   the_filterActionDict = 0;
01210   delete the_undoStack;
01211   the_undoStack = 0;
01212   delete the_popFilterMgr;
01213   the_popFilterMgr = 0;
01214 
01215 #if 0
01216   delete the_weaver;
01217   the_weaver = 0;
01218 #endif
01219 
01220   KConfig* config =  KMKernel::config();
01221   KConfigGroupSaver saver(config, "General");
01222 
01223   if (the_trashFolder) {
01224 
01225     the_trashFolder->close(TRUE);
01226 
01227     if (config->readBoolEntry("empty-trash-on-exit", true))
01228     {
01229       if ( the_trashFolder->count( true ) > 0 )
01230         the_trashFolder->expunge();
01231     }
01232   }
01233 
01234   mICalIface->cleanup();
01235 
01236   QValueList<QGuardedPtr<KMFolder> > folders;
01237   QStringList strList;
01238   KMFolder *folder;
01239   the_folderMgr->createFolderList(&strList, &folders);
01240   for (int i = 0; folders.at(i) != folders.end(); i++)
01241   {
01242     folder = *folders.at(i);
01243     if (!folder || folder->isDir()) continue;
01244     folder->close(TRUE);
01245   }
01246   strList.clear();
01247   folders.clear();
01248   the_searchFolderMgr->createFolderList(&strList, &folders);
01249   for (int i = 0; folders.at(i) != folders.end(); i++)
01250   {
01251     folder = *folders.at(i);
01252     if (!folder || folder->isDir()) continue;
01253     folder->close(TRUE);
01254   }
01255   folderMgr()->writeMsgDict(msgDict());
01256   imapFolderMgr()->writeMsgDict(msgDict());
01257   dimapFolderMgr()->writeMsgDict(msgDict());
01258   delete the_msgIndex;
01259   the_msgIndex = 0;
01260   delete the_folderMgr;
01261   the_folderMgr = 0;
01262   delete the_imapFolderMgr;
01263   the_imapFolderMgr = 0;
01264   delete the_dimapFolderMgr;
01265   the_dimapFolderMgr = 0;
01266   delete the_searchFolderMgr;
01267   the_searchFolderMgr = 0;
01268   delete the_msgDict;
01269   the_msgDict = 0;
01270   delete mConfigureDialog;
01271   mConfigureDialog = 0;
01272   delete mWin;
01273   mWin = 0;
01274 
01275   RecentAddresses::self( KMKernel::config() )->save( KMKernel::config() );
01276   KMKernel::config()->sync();
01277 }
01278 
01279 //Isnīt this obsolete? (sven)
01280 void KMKernel::transferMail(void)
01281 {
01282   QDir dir = QDir::home();
01283   int rc;
01284 
01285   // Stefan: This function is for all the whiners who think that KMail is
01286   // broken because they cannot read mail with pine and do not
01287   // know how to fix this problem with a simple symbolic link  =;-)
01288   // Markus: lol ;-)
01289   if (!dir.cd("KMail")) return;
01290 
01291   rc = KMessageBox::questionYesNo(0,
01292          i18n(
01293         "The directory ~/KMail exists. From now on, KMail uses the "
01294         "directory ~/Mail for its messages.\n"
01295         "KMail can move the contents of the directory ~/KMail into "
01296         "~/Mail, but this will replace existing files with the same "
01297         "name in the directory ~/Mail (e.g. inbox).\n"
01298         "Should KMail move the mail folders now?"));
01299 
01300   if (rc == KMessageBox::No) return;
01301 
01302   dir.cd("/");  // otherwise we lock the directory
01303   testDir("/Mail");
01304   system("mv -f ~/KMail/* ~/Mail");
01305   system("mv -f ~/KMail/.??* ~/Mail");
01306   system("rmdir ~/KMail");
01307 }
01308 
01309 
01310 void KMKernel::ungrabPtrKb(void)
01311 {
01312   if(!KMainWindow::memberList) return;
01313   QWidget* widg = KMainWindow::memberList->first();
01314   Display* dpy;
01315 
01316   if (!widg) return;
01317   dpy = widg->x11Display();
01318   XUngrabKeyboard(dpy, CurrentTime);
01319   XUngrabPointer(dpy, CurrentTime);
01320 }
01321 
01322 
01323 // Message handler
01324 void KMKernel::kmailMsgHandler(QtMsgType aType, const char* aMsg)
01325 {
01326   static int recurse=-1;
01327 
01328   recurse++;
01329 
01330   switch (aType)
01331   {
01332   case QtDebugMsg:
01333   case QtWarningMsg:
01334     kdDebug(5006) << aMsg << endl;
01335     break;
01336 
01337   case QtFatalMsg: // Hm, what about using kdFatal() here?
01338     ungrabPtrKb();
01339     kdDebug(5006) << kapp->caption() << " fatal error "
01340           << aMsg << endl;
01341     KMessageBox::error(0, aMsg);
01342     abort();
01343   }
01344 
01345   recurse--;
01346 }
01347 void KMKernel::dumpDeadLetters()
01348 {
01349   if (shuttingDown())
01350     return; //All documents should be saved before shutting down is set!
01351   mDeadLetterTimer->stop();
01352   QWidget *win;
01353   QDir dir = QDir::home();
01354   QString fname = dir.path();
01355   QFile::remove(fname + "/dead.letter.tmp");
01356   if (KMainWindow::memberList) {
01357     QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
01358 
01359     while ((win = it.current()) != 0) {
01360       ++it;
01361       if (::qt_cast<KMComposeWin*>(win)) ((KMComposeWin*)win)->deadLetter();
01362       //    delete win; // WABA: Don't delete, we might crash in there!
01363     }
01364   }
01365   QFile::remove(fname + "/dead.letter");
01366   dir.rename("dead.letter.tmp","dead.letter");
01367   if ( mDeadLetterInterval )
01368     mDeadLetterTimer->start(mDeadLetterInterval);
01369 }
01370 
01371 
01372 
01373 void KMKernel::action(bool mailto, bool check, const QString &to,
01374                       const QString &cc, const QString &bcc,
01375                       const QString &subj, const QString &body,
01376                       const KURL &messageFile,
01377                       const KURL::List &attachURLs)
01378 {
01379   if (mailto)
01380     openComposer (to, cc, bcc, subj, body, 0, messageFile, attachURLs);
01381   else
01382     openReader( check );
01383 
01384   if (check)
01385     checkMail();
01386   //Anything else?
01387 }
01388 
01389 void KMKernel::byteArrayToRemoteFile(const QByteArray &aData, const KURL &aURL,
01390   bool overwrite)
01391 {
01392   // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether
01393   KIO::Job *job = KIO::put(aURL, -1, overwrite, FALSE);
01394   putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0;
01395   mPutJobs.insert(job, pd);
01396   connect(job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
01397     SLOT(slotDataReq(KIO::Job*,QByteArray&)));
01398   connect(job, SIGNAL(result(KIO::Job*)),
01399     SLOT(slotResult(KIO::Job*)));
01400 }
01401 
01402 void KMKernel::slotDataReq(KIO::Job *job, QByteArray &data)
01403 {
01404   // send the data in 64 KB chunks
01405   const int MAX_CHUNK_SIZE = 64*1024;
01406   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01407   assert(it != mPutJobs.end());
01408   int remainingBytes = (*it).data.size() - (*it).offset;
01409   if( remainingBytes > MAX_CHUNK_SIZE )
01410   {
01411     // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
01412     data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE );
01413     (*it).offset += MAX_CHUNK_SIZE;
01414     //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes ("
01415     //                << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
01416   }
01417   else
01418   {
01419     // send the remaining bytes to the receiver (deep copy)
01420     data.duplicate( (*it).data.data() + (*it).offset, remainingBytes );
01421     (*it).data = QByteArray();
01422     (*it).offset = 0;
01423     //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n";
01424   }
01425 }
01426 
01427 void KMKernel::slotResult(KIO::Job *job)
01428 {
01429   QMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job);
01430   assert(it != mPutJobs.end());
01431   if (job->error())
01432   {
01433     if (job->error() == KIO::ERR_FILE_ALREADY_EXIST)
01434     {
01435       if (KMessageBox::warningContinueCancel(0,
01436         i18n("File %1 exists.\nDo you want to replace it?")
01437         .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace"))
01438         == KMessageBox::Continue)
01439         byteArrayToRemoteFile((*it).data, (*it).url, TRUE);
01440     }
01441     else job->showErrorDialog();
01442   }
01443   mPutJobs.remove(it);
01444 }
01445 
01446 void KMKernel::slotRequestConfigSync() {
01447   // ### FIXME: delay as promised in the kdoc of this function ;-)
01448   KMKernel::config()->sync();
01449 }
01450 
01451 void KMKernel::slotShowConfigurationDialog()
01452 {
01453   if( !mConfigureDialog ) {
01454     mConfigureDialog = new ConfigureDialog( 0, "configure", false );
01455     connect( mConfigureDialog, SIGNAL( configCommitted() ),
01456              this, SLOT( slotConfigChanged() ) );
01457   }
01458 
01459   if( mConfigureDialog->isHidden() )
01460     mConfigureDialog->show();
01461   else
01462     mConfigureDialog->raise();
01463 }
01464 
01465 void KMKernel::slotConfigChanged()
01466 {
01467   readConfig();
01468   emit configChanged();
01469 }
01470 
01471 bool KMKernel::haveSystemTrayApplet()
01472 {
01473   return !systemTrayApplets.isEmpty();
01474 }
01475 
01476 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet )
01477 {
01478   if ( systemTrayApplets.findIndex( applet ) == -1 ) {
01479     systemTrayApplets.append( applet );
01480     return true;
01481   }
01482   else
01483     return false;
01484 }
01485 
01486 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet )
01487 {
01488   QValueList<const KSystemTray*>::iterator it =
01489     systemTrayApplets.find( applet );
01490   if ( it != systemTrayApplets.end() ) {
01491     systemTrayApplets.remove( it );
01492     return true;
01493   }
01494   else
01495     return false;
01496 }
01497 
01498 void KMKernel::emergencyExit( const QString& reason )
01499 {
01500   QString mesg;
01501   if ( reason.length() == 0 ) {
01502     mesg = i18n("KMail encountered a fatal error and will terminate now");
01503   }
01504   else {
01505     mesg = i18n("KMail encountered a fatal error and will "
01506                       "terminate now.\nThe error was:\n%1").arg( reason );
01507   }
01508 
01509   kdWarning() << mesg << endl;
01510   KNotifyClient::userEvent( 0, mesg, KNotifyClient::Messagebox, KNotifyClient::Error );
01511 
01512   ::exit(1);
01513 }
01514 
01518 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder)
01519 {
01520   assert( folder );
01521   if ( folder == the_outboxFolder || folder == the_draftsFolder )
01522     return true;
01523 
01524   QString idString = folder->idString();
01525   if ( idString.isEmpty() ) return false;
01526 
01527   // search the identities if the folder matches the drafts-folder
01528   const KPIM::IdentityManager * im = identityManager();
01529   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
01530     if ( (*it).drafts() == idString ) return true;
01531   return false;
01532 }
01533 
01534 bool KMKernel::folderIsTrash(KMFolder * folder)
01535 {
01536   assert(folder);
01537   if (folder == the_trashFolder) return true;
01538   QStringList actList = acctMgr()->getAccounts(false);
01539   QStringList::Iterator it( actList.begin() );
01540   for( ; it != actList.end() ; ++it ) {
01541     KMAccount* act = acctMgr()->findByName( *it );
01542     if ( act && ( act->trash() == folder->idString() ) )
01543       return true;
01544   }
01545   return false;
01546 }
01547 
01548 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder )
01549 {
01550   assert( folder );
01551   if ( folder == the_sentFolder )
01552     return true;
01553 
01554   QString idString = folder->idString();
01555   if ( idString.isEmpty() ) return false;
01556 
01557   // search the identities if the folder matches the sent-folder
01558   const KPIM::IdentityManager * im = identityManager();
01559   for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it )
01560     if ( (*it).fcc() == idString ) return true;
01561   return false;
01562 }
01563 
01564 KPIM::IdentityManager * KMKernel::identityManager() {
01565   if ( !mIdentityManager ) {
01566     kdDebug(5006) << "instantating KPIM::IdentityManager" << endl;
01567     mIdentityManager = new KPIM::IdentityManager( false, this, "mIdentityManager" );
01568   }
01569   return mIdentityManager;
01570 }
01571 
01572 KMMsgDict *KMKernel::msgDict()
01573 {
01574     if (the_msgDict)
01575     return the_msgDict;
01576     the_msgDict = new KMMsgDict;
01577     folderMgr()->readMsgDict(msgDict());
01578     imapFolderMgr()->readMsgDict(msgDict());
01579     dimapFolderMgr()->readMsgDict(msgDict());
01580     return the_msgDict;
01581 }
01582 
01583 KMMsgIndex *KMKernel::msgIndex()
01584 {
01585     return the_msgIndex;
01586 }
01587 
01588 KMainWindow* KMKernel::mainWin()
01589 {
01590   if (KMainWindow::memberList) {
01591     KMainWindow *kmWin = 0;
01592 
01593     // First look for a KMMainWin.
01594     for (kmWin = KMainWindow::memberList->first(); kmWin;
01595          kmWin = KMainWindow::memberList->next())
01596       if (kmWin->isA("KMMainWin"))
01597         return kmWin;
01598 
01599     // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
01600     // case we are running inside Kontact) because we anyway only need
01601     // it for modal message boxes and for KNotify events.
01602     kmWin = KMainWindow::memberList->first();
01603     if ( kmWin )
01604       return kmWin;
01605   }
01606 
01607   // There's not a single KMainWindow. Create a KMMainWin.
01608   // This could happen if we want to pop up an error message
01609   // while we are still doing the startup wizard and no other
01610   // KMainWindow is running.
01611   mWin = new KMMainWin;
01612   return mWin;
01613 }
01614 
01615 
01619 void KMKernel::slotEmptyTrash()
01620 {
01621   QString title = i18n("Empty Trash");
01622   QString text = i18n("Are you sure you want to empty the trash folders of all accounts?");
01623   if (KMessageBox::warningContinueCancel(0, text, title,
01624                                          KStdGuiItem::cont(), "confirm_empty_trash")
01625       != KMessageBox::Continue)
01626   {
01627     return;
01628   }
01629 
01630   for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next())
01631   {
01632     KMFolder* trash = findFolderById(acct->trash());
01633     if (trash)
01634     {
01635       trash->expunge();
01636     }
01637   }
01638 }
01639 
01640 KConfig* KMKernel::config()
01641 {
01642   assert(mySelf);
01643   if (!mySelf->mConfig)
01644   {
01645     mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" );
01646     // Check that all updates have been run on the config file:
01647     KMail::checkConfigUpdates();
01648   }
01649   return mySelf->mConfig;
01650 }
01651 
01652 KMailICalIfaceImpl& KMKernel::iCalIface()
01653 {
01654   assert( mICalIface );
01655   return *mICalIface;
01656 }
01657 
01658 void KMKernel::selectFolder( QString folderPath )
01659 {
01660   kdDebug(5006)<<"Selecting a folder "<<folderPath<<endl;
01661   const QString localPrefix = "/Local";
01662   KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath );
01663   if ( !folder && folderPath.startsWith( localPrefix ) )
01664     folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) );
01665   if ( !folder )
01666     folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath );
01667   if ( !folder )
01668     folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath );
01669   Q_ASSERT( folder );
01670 
01671   KMMainWidget *widget = getKMMainWidget();
01672   Q_ASSERT( widget );
01673   if ( !widget )
01674     return;
01675 
01676   KMFolderTree *tree = widget->folderTree();
01677   tree->doFolderSelected( tree->indexOfFolder( folder ) );
01678   tree->ensureItemVisible( tree->indexOfFolder( folder ) );
01679 }
01680 
01681 KMMainWidget *KMKernel::getKMMainWidget()
01682 {
01683   //This could definitely use a speadup
01684   QWidgetList *l = kapp->topLevelWidgets();
01685   QWidgetListIt it( *l );
01686   QWidget *wid;
01687 
01688   while ( ( wid = it.current() ) != 0 ) {
01689     ++it;
01690     QObjectList *l2 = wid->topLevelWidget()->queryList( "KMMainWidget" );
01691     if (l2 && l2->first()) {
01692       KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2->first() );
01693       Q_ASSERT( kmmw );
01694       delete l2;
01695       delete l;
01696       return kmmw;
01697     }
01698     delete l2;
01699   }
01700   delete l;
01701   return 0;
01702 }
01703 
01704 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
01705 {
01706   // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
01707   // a stable kmail release goes out with a nasty bug in CompactionJob...
01708   KConfigGroup generalGroup( config(), "General" );
01709 
01710   if ( generalGroup.readBoolEntry( "auto-expiring", true ) ) {
01711     the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
01712     the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
01713     the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ );
01714     // the_searchFolderMgr: no expiry there
01715   }
01716 
01717   if ( generalGroup.readBoolEntry( "auto-compaction", true ) ) {
01718     the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
01719     // the_imapFolderMgr: no compaction
01720     the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ );
01721     // the_searchFolderMgr: no compaction
01722   }
01723 
01724 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
01725   mBackgroundTasksTimer->start( 60 * 1000, true ); // check again in 1 minute
01726 #else
01727   mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours
01728 #endif
01729 
01730 }
01731 
01732 void KMKernel::expireAllFoldersNow() // called by the GUI
01733 {
01734   the_folderMgr->expireAllFolders( true /*immediate*/ );
01735   the_imapFolderMgr->expireAllFolders( true /*immediate*/ );
01736   the_dimapFolderMgr->expireAllFolders( true /*immediate*/ );
01737 }
01738 
01739 void KMKernel::compactAllFolders() // called by the GUI
01740 {
01741   the_folderMgr->compactAllFolders( true /*immediate*/ );
01742   //the_imapFolderMgr->compactAllFolders( true /*immediate*/ );
01743   the_dimapFolderMgr->compactAllFolders( true /*immediate*/ );
01744 }
01745 
01746 KMFolder* KMKernel::findFolderById( const QString& idString )
01747 {
01748   KMFolder * folder = the_folderMgr->findIdString( idString );
01749   if ( !folder )
01750     folder = the_imapFolderMgr->findIdString( idString );
01751   if ( !folder )
01752     folder = the_dimapFolderMgr->findIdString( idString );
01753   if ( !folder )
01754     folder = the_searchFolderMgr->findIdString( idString );
01755   return folder;
01756 }
01757 
01758 ::KIMProxy* KMKernel::imProxy()
01759 {
01760   return KIMProxy::instance( kapp->dcopClient() );
01761 }
01762 
01763 void KMKernel::enableMailCheck()
01764 {
01765   mMailCheckAborted = false;
01766 }
01767 
01768 bool KMKernel::mailCheckAborted() const
01769 {
01770   return mMailCheckAborted;
01771 }
01772 
01773 void KMKernel::abortMailCheck()
01774 {
01775   mMailCheckAborted = true;
01776 }
01777 
01778 bool KMKernel::canQueryClose()
01779 {
01780   if ( KMMainWidget::mainWidgetList() &&
01781        KMMainWidget::mainWidgetList()->count() > 1 )
01782     return true;
01783   KMMainWidget *widget = getKMMainWidget();
01784   if ( !widget )
01785     return true;
01786   KMSystemTray* systray = widget->systray();
01787   if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
01788     systray->hideKMail();
01789     return false;
01790   } else if ( systray && systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
01791     systray->show();
01792     systray->hideKMail();
01793     return false;
01794   }
01795   return true;
01796 }
01797 
01798 void KMKernel::messageCountChanged()
01799 {
01800   mTimeOfLastMessageCountChange = ::time( 0 );
01801 }
01802 
01803 int KMKernel::timeOfLastMessageCountChange() const
01804 {
01805   return mTimeOfLastMessageCountChange;
01806 }
01807 
01808 #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 Mon Apr 4 06:44:11 2005 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003