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