kmkernel.cpp
00001 /* -*- mode: C++; c-file-style: "gnu" -*- */ 00002 #ifdef HAVE_CONFIG_H 00003 #include <config.h> 00004 #endif 00005 00006 #include "config.h" 00007 #include "kmkernel.h" 00008 00009 #include <weaver.h> 00010 #include <weaverlogger.h> 00011 00012 #include "globalsettings.h" 00013 #include "broadcaststatus.h" 00014 using KPIM::BroadcastStatus; 00015 #include "kmstartup.h" 00016 #include "index.h" 00017 #include "kmmainwin.h" 00018 #include "composer.h" 00019 #include "kmmsgpart.h" 00020 #include "kmreadermainwin.h" 00021 #include "kmfoldermgr.h" 00022 #include "kmfoldercachedimap.h" 00023 #include "kmacctcachedimap.h" 00024 #include "kmfiltermgr.h" 00025 #include "kmfilteraction.h" 00026 #include "kmheaders.h" 00027 #define REALLY_WANT_KMSENDER 00028 #include "kmsender.h" 00029 #undef REALLY_WANT_KMSENDER 00030 #include "undostack.h" 00031 #include "accountmanager.h" 00032 using KMail::AccountManager; 00033 #include <libkdepim/kfileio.h> 00034 #include "kmversion.h" 00035 #include "kmreaderwin.h" 00036 #include "kmmainwidget.h" 00037 #include "kmfoldertree.h" 00038 #include "recentaddresses.h" 00039 using KRecentAddress::RecentAddresses; 00040 #include "kmmsgdict.h" 00041 #include <libkpimidentities/identity.h> 00042 #include <libkpimidentities/identitymanager.h> 00043 #include "configuredialog.h" 00044 #include "kmcommands.h" 00045 #include "kmsystemtray.h" 00046 #include "transportmanager.h" 00047 #include "importarchivedialog.h" 00048 00049 #include <kwin.h> 00050 #include "kmailicalifaceimpl.h" 00051 #include "mailserviceimpl.h" 00052 using KMail::MailServiceImpl; 00053 #include "mailcomposerIface.h" 00054 #include "folderIface.h" 00055 using KMail::FolderIface; 00056 #include "jobscheduler.h" 00057 #include "templateparser.h" 00058 00059 #include <kapplication.h> 00060 #include <kmessagebox.h> 00061 #include <knotifyclient.h> 00062 #include <kstaticdeleter.h> 00063 #include <kstandarddirs.h> 00064 #include <kconfig.h> 00065 #include <kprogress.h> 00066 #include <kpassivepopup.h> 00067 #include <dcopclient.h> 00068 #include <ksystemtray.h> 00069 #include <kpgp.h> 00070 #include <kdebug.h> 00071 #include <kio/netaccess.h> 00072 #include <kwallet.h> 00073 using KWallet::Wallet; 00074 #include "actionscheduler.h" 00075 00076 #include <qutf7codec.h> 00077 #include <tqvbox.h> 00078 #include <tqdir.h> 00079 #include <tqwidgetlist.h> 00080 #include <tqobjectlist.h> 00081 00082 #include <sys/types.h> 00083 #include <dirent.h> 00084 #include <sys/stat.h> 00085 #include <unistd.h> 00086 #include <stdio.h> 00087 #include <stdlib.h> 00088 #include <assert.h> 00089 00090 #include <X11/Xlib.h> 00091 #include <fixx11h.h> 00092 #include <kcmdlineargs.h> 00093 #include <kstartupinfo.h> 00094 00095 KMKernel *KMKernel::mySelf = 0; 00096 static bool s_askingToGoOnline = false; 00097 00098 /********************************************************************/ 00099 /* Constructor and destructor */ 00100 /********************************************************************/ 00101 KMKernel::KMKernel (TQObject *parent, const char *name) : 00102 DCOPObject("KMailIface"), TQObject(parent, name), 00103 mIdentityManager(0), mConfigureDialog(0), 00104 mContextMenuShown( false ), mWallet( 0 ) 00105 { 00106 kdDebug(5006) << "KMKernel::KMKernel" << endl; 00107 mySelf = this; 00108 the_startingUp = true; 00109 closed_by_user = true; 00110 the_firstInstance = true; 00111 the_msgIndex = 0; 00112 00113 the_inboxFolder = 0; 00114 the_outboxFolder = 0; 00115 the_sentFolder = 0; 00116 the_trashFolder = 0; 00117 the_draftsFolder = 0; 00118 the_templatesFolder = 0; 00119 00120 the_folderMgr = 0; 00121 the_imapFolderMgr = 0; 00122 the_dimapFolderMgr = 0; 00123 the_searchFolderMgr = 0; 00124 the_undoStack = 0; 00125 the_acctMgr = 0; 00126 the_filterMgr = 0; 00127 the_popFilterMgr = 0; 00128 the_filterActionDict = 0; 00129 the_msgSender = 0; 00130 mWin = 0; 00131 mMailCheckAborted = false; 00132 00133 // make sure that we check for config updates before doing anything else 00134 KMKernel::config(); 00135 // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it 00136 // so better do it here, than in some code where changing the group of config() 00137 // would be unexpected 00138 GlobalSettings::self(); 00139 00140 // Set up DCOP interface 00141 mICalIface = new KMailICalIfaceImpl(); 00142 00143 mJobScheduler = new JobScheduler( this ); 00144 00145 mXmlGuiInstance = 0; 00146 00147 new Kpgp::Module(); 00148 00149 // register our own (libkdenetwork) utf-7 codec as long as TQt 00150 // doesn't have it's own: 00151 if ( !TQTextCodec::codecForName("utf-7") ) { 00152 kdDebug(5006) << "No TQt-native utf-7 codec found; registering TQUtf7Codec from libkdenetwork" << endl; 00153 (void) new TQUtf7Codec(); 00154 } 00155 00156 // In the case of Japan. Japanese locale name is "eucjp" but 00157 // The Japanese mail systems normally used "iso-2022-jp" of locale name. 00158 // We want to change locale name from eucjp to iso-2022-jp at KMail only. 00159 if ( TQCString(TQTextCodec::codecForLocale()->name()).lower() == "eucjp" ) 00160 { 00161 netCodec = TQTextCodec::codecForName("jis7"); 00162 // TQTextCodec *cdc = TQTextCodec::codecForName("jis7"); 00163 // TQTextCodec::setCodecForLocale(cdc); 00164 // KGlobal::locale()->setEncoding(cdc->mibEnum()); 00165 } else { 00166 netCodec = TQTextCodec::codecForLocale(); 00167 } 00168 mMailService = new MailServiceImpl(); 00169 00170 connectDCOPSignal( 0, 0, "kmailSelectFolder(TQString)", 00171 "selectFolder(TQString)", false ); 00172 } 00173 00174 KMKernel::~KMKernel () 00175 { 00176 TQMap<KIO::Job*, putData>::Iterator it = mPutJobs.begin(); 00177 while ( it != mPutJobs.end() ) 00178 { 00179 KIO::Job *job = it.key(); 00180 mPutJobs.remove( it ); 00181 job->kill(); 00182 it = mPutJobs.begin(); 00183 } 00184 00185 delete mICalIface; 00186 mICalIface = 0; 00187 delete mMailService; 00188 mMailService = 0; 00189 00190 GlobalSettings::self()->writeConfig(); 00191 delete mWallet; 00192 mWallet = 0; 00193 mySelf = 0; 00194 kdDebug(5006) << "KMKernel::~KMKernel" << endl; 00195 } 00196 00197 bool KMKernel::handleCommandLine( bool noArgsOpensReader ) 00198 { 00199 TQString to, cc, bcc, subj, body; 00200 QCStringList customHeaders; 00201 KURL messageFile; 00202 KURL::List attachURLs; 00203 bool mailto = false; 00204 bool checkMail = false; 00205 bool viewOnly = false; 00206 bool calledWithSession = false; // for ignoring '-session foo' 00207 00208 // process args: 00209 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 00210 if (!args->getOption("subject").isNull()) 00211 { 00212 subj = TQString::fromLocal8Bit(args->getOption("subject")); 00213 // if kmail is called with 'kmail -session abc' then this doesn't mean 00214 // that the user wants to send a message with subject "ession" but 00215 // (most likely) that the user clicked on KMail's system tray applet 00216 // which results in KMKernel::raise() calling "kmail kmail newInstance" 00217 // via dcop which apparently executes the application with the original 00218 // command line arguments and those include "-session ..." if 00219 // kmail/kontact was restored by session management 00220 if ( subj == "ession" ) { 00221 subj = TQString(); 00222 calledWithSession = true; 00223 } 00224 else 00225 mailto = true; 00226 } 00227 00228 if (!args->getOption("cc").isNull()) 00229 { 00230 mailto = true; 00231 cc = TQString::fromLocal8Bit(args->getOption("cc")); 00232 } 00233 00234 if (!args->getOption("bcc").isNull()) 00235 { 00236 mailto = true; 00237 bcc = TQString::fromLocal8Bit(args->getOption("bcc")); 00238 } 00239 00240 if (!args->getOption("msg").isNull()) 00241 { 00242 mailto = true; 00243 messageFile.setPath( TQString::fromLocal8Bit(args->getOption("msg")) ); 00244 } 00245 00246 if (!args->getOption("body").isNull()) 00247 { 00248 mailto = true; 00249 body = TQString::fromLocal8Bit(args->getOption("body")); 00250 } 00251 00252 QCStringList attachList = args->getOptionList("attach"); 00253 if (!attachList.isEmpty()) 00254 { 00255 mailto = true; 00256 for ( QCStringList::Iterator it = attachList.begin() ; it != attachList.end() ; ++it ) 00257 if ( !(*it).isEmpty() ) 00258 attachURLs += KURL( TQString::fromLocal8Bit( *it ) ); 00259 } 00260 00261 customHeaders = args->getOptionList("header"); 00262 00263 if (args->isSet("composer")) 00264 mailto = true; 00265 00266 if (args->isSet("check")) 00267 checkMail = true; 00268 00269 if ( !args->getOption( "view" ).isNull() ) { 00270 viewOnly = true; 00271 const TQString filename = 00272 TQString::fromLocal8Bit( args->getOption( "view" ) ); 00273 messageFile = KURL::fromPathOrURL( filename ); 00274 if ( !messageFile.isValid() ) { 00275 messageFile = KURL(); 00276 messageFile.setPath( filename ); 00277 } 00278 } 00279 00280 if ( !calledWithSession ) { 00281 // only read additional command line arguments if kmail/kontact is 00282 // not called with "-session foo" 00283 for(int i= 0; i < args->count(); i++) 00284 { 00285 if (strncasecmp(args->arg(i),"mailto:",7)==0) 00286 to += args->url(i).path() + ", "; 00287 else { 00288 TQString tmpArg = TQString::fromLocal8Bit( args->arg(i) ); 00289 KURL url( tmpArg ); 00290 if ( url.isValid() ) 00291 attachURLs += url; 00292 else 00293 to += tmpArg + ", "; 00294 } 00295 mailto = true; 00296 } 00297 if ( !to.isEmpty() ) { 00298 // cut off the superfluous trailing ", " 00299 to.truncate( to.length() - 2 ); 00300 } 00301 } 00302 00303 if ( !calledWithSession ) 00304 args->clear(); 00305 00306 if ( !noArgsOpensReader && !mailto && !checkMail && !viewOnly ) 00307 return false; 00308 00309 if ( viewOnly ) 00310 viewMessage( messageFile ); 00311 else 00312 action( mailto, checkMail, to, cc, bcc, subj, body, messageFile, 00313 attachURLs, customHeaders ); 00314 return true; 00315 } 00316 00317 /********************************************************************/ 00318 /* DCOP-callable, and command line actions */ 00319 /********************************************************************/ 00320 void KMKernel::checkMail () //might create a new reader but won't show!! 00321 { 00322 if ( !kmkernel->askToGoOnline() ) 00323 return; 00324 kmkernel->acctMgr()->checkMail(false); 00325 } 00326 00327 TQStringList KMKernel::accounts() 00328 { 00329 if( kmkernel->acctMgr() ) 00330 return kmkernel->acctMgr()->getAccounts(); 00331 return TQStringList(); 00332 } 00333 00334 void KMKernel::checkAccount (const TQString &account) //might create a new reader but won't show!! 00335 { 00336 kdDebug(5006) << "KMKernel::checkMail called" << endl; 00337 00338 KMAccount* acct = kmkernel->acctMgr()->findByName(account); 00339 if (acct) 00340 kmkernel->acctMgr()->singleCheckMail(acct, false); 00341 } 00342 00343 void KMKernel::loadProfile( const TQString& ) 00344 { 00345 } 00346 00347 void KMKernel::saveToProfile( const TQString& ) const 00348 { 00349 } 00350 00351 void KMKernel::openReader( bool onlyCheck ) 00352 { 00353 mWin = 0; 00354 KMainWindow *ktmw = 0; 00355 kdDebug(5006) << "KMKernel::openReader called" << endl; 00356 00357 if (KMainWindow::memberList) 00358 for (ktmw = KMainWindow::memberList->first(); ktmw; 00359 ktmw = KMainWindow::memberList->next()) 00360 if (ktmw->isA("KMMainWin")) 00361 break; 00362 00363 bool activate; 00364 if (ktmw) { 00365 mWin = (KMMainWin *) ktmw; 00366 activate = !onlyCheck; // existing window: only activate if not --check 00367 if ( activate ) 00368 mWin->show(); 00369 } else { 00370 mWin = new KMMainWin; 00371 mWin->show(); 00372 activate = false; // new window: no explicit activation (#73591) 00373 } 00374 00375 if ( activate ) { 00376 // Activate window - doing this instead of KWin::activateWindow(mWin->winId()); 00377 // so that it also works when called from KMailApplication::newInstance() 00378 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY 00379 KStartupInfo::setNewStartupId( mWin, kapp->startupId() ); 00380 #endif 00381 } 00382 } 00383 00384 int KMKernel::openComposer (const TQString &to, const TQString &cc, 00385 const TQString &bcc, const TQString &subject, 00386 const TQString &body, int hidden, 00387 const KURL &messageFile, 00388 const KURL::List &attachURLs, 00389 const QCStringList &customHeaders) 00390 { 00391 kdDebug(5006) << "KMKernel::openComposer called" << endl; 00392 KMMessage *msg = new KMMessage; 00393 msg->initHeader(); 00394 msg->setCharset("utf-8"); 00395 // tentatively decode to, cc and bcc because invokeMailer calls us with 00396 // RFC 2047 encoded addresses in order to protect non-ASCII email addresses 00397 if (!to.isEmpty()) 00398 msg->setTo( KMMsgBase::decodeRFC2047String( to.latin1() ) ); 00399 if (!cc.isEmpty()) 00400 msg->setCc( KMMsgBase::decodeRFC2047String( cc.latin1() ) ); 00401 if (!bcc.isEmpty()) 00402 msg->setBcc( KMMsgBase::decodeRFC2047String( bcc.latin1() ) ); 00403 if (!subject.isEmpty()) msg->setSubject(subject); 00404 if (!messageFile.isEmpty() && messageFile.isLocalFile()) { 00405 TQCString str = KPIM::kFileToString( messageFile.path(), true, false ); 00406 if( !str.isEmpty() ) { 00407 msg->setBody( TQString(TQString::fromLocal8Bit( str )).utf8() ); 00408 } else { 00409 TemplateParser parser( msg, TemplateParser::NewMessage ); 00410 parser.process( NULL, NULL ); 00411 } 00412 } 00413 else if (!body.isEmpty()) 00414 { 00415 msg->setBody(body.utf8()); 00416 } 00417 else 00418 { 00419 TemplateParser parser( msg, TemplateParser::NewMessage ); 00420 parser.process( NULL, NULL ); 00421 } 00422 00423 if (!customHeaders.isEmpty()) 00424 { 00425 for ( QCStringList::ConstIterator it = customHeaders.begin() ; it != customHeaders.end() ; ++it ) 00426 if ( !(*it).isEmpty() ) 00427 { 00428 const int pos = (*it).find( ':' ); 00429 if ( pos > 0 ) 00430 { 00431 TQCString header, value; 00432 header = (*it).left( pos ).stripWhiteSpace(); 00433 value = (*it).mid( pos+1 ).stripWhiteSpace(); 00434 if ( !header.isEmpty() && !value.isEmpty() ) 00435 msg->setHeaderField( header, value ); 00436 } 00437 } 00438 } 00439 00440 KMail::Composer * cWin = KMail::makeComposer( msg ); 00441 cWin->setCharset("", true); 00442 for ( KURL::List::ConstIterator it = attachURLs.begin() ; it != attachURLs.end() ; ++it ) 00443 cWin->addAttach((*it)); 00444 if (hidden == 0) { 00445 cWin->show(); 00446 // Activate window - doing this instead of KWin::activateWindow(cWin->winId()); 00447 // so that it also works when called from KMailApplication::newInstance() 00448 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY 00449 KStartupInfo::setNewStartupId( cWin, kapp->startupId() ); 00450 #endif 00451 } 00452 return 1; 00453 } 00454 00455 00456 int KMKernel::openComposer (const TQString &to, const TQString &cc, 00457 const TQString &bcc, const TQString &subject, 00458 const TQString &body, int hidden, 00459 const TQString &attachName, 00460 const TQCString &attachCte, 00461 const TQCString &attachData, 00462 const TQCString &attachType, 00463 const TQCString &attachSubType, 00464 const TQCString &attachParamAttr, 00465 const TQString &attachParamValue, 00466 const TQCString &attachContDisp ) 00467 { 00468 kdDebug(5006) << "KMKernel::openComposer called (deprecated version)" << endl; 00469 00470 return openComposer ( to, cc, bcc, subject, body, hidden, 00471 attachName, attachCte, attachData, 00472 attachType, attachSubType, attachParamAttr, 00473 attachParamValue, attachContDisp, TQCString() ); 00474 } 00475 00476 int KMKernel::openComposer (const TQString &to, const TQString &cc, 00477 const TQString &bcc, const TQString &subject, 00478 const TQString &body, int hidden, 00479 const TQString &attachName, 00480 const TQCString &attachCte, 00481 const TQCString &attachData, 00482 const TQCString &attachType, 00483 const TQCString &attachSubType, 00484 const TQCString &attachParamAttr, 00485 const TQString &attachParamValue, 00486 const TQCString &attachContDisp, 00487 const TQCString &attachCharset ) 00488 { 00489 kdDebug(5006) << "KMKernel::openComposer called (deprecated version)" << endl; 00490 return openComposer ( to, cc, bcc, subject, body, hidden, 00491 attachName, attachCte, attachData, 00492 attachType, attachSubType, attachParamAttr, 00493 attachParamValue, attachContDisp, attachCharset, 0 ); 00494 } 00495 00496 int KMKernel::openComposer (const TQString &to, const TQString &cc, 00497 const TQString &bcc, const TQString &subject, 00498 const TQString &body, int hidden, 00499 const TQString &attachName, 00500 const TQCString &attachCte, 00501 const TQCString &attachData, 00502 const TQCString &attachType, 00503 const TQCString &attachSubType, 00504 const TQCString &attachParamAttr, 00505 const TQString &attachParamValue, 00506 const TQCString &attachContDisp, 00507 const TQCString &attachCharset, 00508 unsigned int identity ) 00509 { 00510 kdDebug(5006) << "KMKernel::openComposer()" << endl; 00511 00512 KMMessage *msg = new KMMessage; 00513 KMMessagePart *msgPart = 0; 00514 msg->initHeader(); 00515 msg->setCharset( "utf-8" ); 00516 if ( !cc.isEmpty() ) msg->setCc(cc); 00517 if ( !bcc.isEmpty() ) msg->setBcc(bcc); 00518 if ( !subject.isEmpty() ) msg->setSubject(subject); 00519 if ( !to.isEmpty() ) msg->setTo(to); 00520 if ( identity > 0 ) msg->setHeaderField( "X-KMail-Identity", TQString::number( identity ) ); 00521 if ( !body.isEmpty() ) { 00522 msg->setBody(body.utf8()); 00523 } else { 00524 TemplateParser parser( msg, TemplateParser::NewMessage ); 00525 parser.process( NULL, NULL ); 00526 } 00527 00528 bool iCalAutoSend = false; 00529 bool noWordWrap = false; 00530 bool isICalInvitation = false; 00531 KConfigGroup options( config(), "Groupware" ); 00532 if ( !attachData.isEmpty() ) { 00533 isICalInvitation = attachName == "cal.ics" && 00534 attachType == "text" && 00535 attachSubType == "calendar" && 00536 attachParamAttr == "method"; 00537 // Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474) 00538 if ( isICalInvitation && bcc.isEmpty() ) 00539 msg->setBcc( "" ); 00540 if ( isICalInvitation && 00541 GlobalSettings::self()->legacyBodyInvites() ) { 00542 // KOrganizer invitation caught and to be sent as body instead 00543 msg->setBody( attachData ); 00544 msg->setHeaderField( "Content-Type", 00545 TQString( "text/calendar; method=%1; " 00546 "charset=\"utf-8\"" ). 00547 arg( attachParamValue ) ); 00548 00549 iCalAutoSend = true; // no point in editing raw ICAL 00550 noWordWrap = true; // we shant word wrap inline invitations 00551 } else { 00552 // Just do what we're told to do 00553 msgPart = new KMMessagePart; 00554 msgPart->setName( attachName ); 00555 msgPart->setCteStr( attachCte ); 00556 msgPart->setBodyEncoded( attachData ); 00557 msgPart->setTypeStr( attachType ); 00558 msgPart->setSubtypeStr( attachSubType ); 00559 msgPart->setParameter( attachParamAttr, attachParamValue ); 00560 if( ! GlobalSettings::self()->exchangeCompatibleInvitations() ) { 00561 msgPart->setContentDisposition( attachContDisp ); 00562 } 00563 if( !attachCharset.isEmpty() ) { 00564 // kdDebug(5006) << "KMKernel::openComposer set attachCharset to " 00565 // << attachCharset << endl; 00566 msgPart->setCharset( attachCharset ); 00567 } 00568 // Don't show the composer window, if the automatic sending is checked 00569 KConfigGroup options( config(), "Groupware" ); 00570 iCalAutoSend = options.readBoolEntry( "AutomaticSending", true ); 00571 } 00572 } 00573 00574 KMail::Composer * cWin = KMail::makeComposer(); 00575 cWin->setMsg( msg, !isICalInvitation /* mayAutoSign */ ); 00576 cWin->setSigningAndEncryptionDisabled( isICalInvitation 00577 && GlobalSettings::self()->legacyBodyInvites() ); 00578 cWin->setAutoDelete( true ); 00579 if( noWordWrap ) 00580 cWin->disableWordWrap(); 00581 else 00582 cWin->setCharset( "", true ); 00583 if ( msgPart ) 00584 cWin->addAttach(msgPart); 00585 00586 if ( isICalInvitation ) { 00587 cWin->disableRecipientNumberCheck(); 00588 cWin->disableForgottenAttachmentsCheck(); 00589 } 00590 00591 if ( hidden == 0 && !iCalAutoSend ) { 00592 cWin->show(); 00593 // Activate window - doing this instead of KWin::activateWindow(cWin->winId()); 00594 // so that it also works when called from KMailApplication::newInstance() 00595 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY 00596 KStartupInfo::setNewStartupId( cWin, kapp->startupId() ); 00597 #endif 00598 } else { 00599 cWin->setAutoDeleteWindow( true ); 00600 cWin->slotSendNow(); 00601 } 00602 00603 return 1; 00604 } 00605 00606 void KMKernel::setDefaultTransport( const TQString & transport ) 00607 { 00608 TQStringList availTransports = KMail::TransportManager::transportNames(); 00609 TQStringList::const_iterator it = availTransports.find( transport ); 00610 if ( it == availTransports.end() ) { 00611 kdWarning() << "The transport you entered is not available" << endl; 00612 return; 00613 } 00614 GlobalSettings::self()->setDefaultTransport( transport ); 00615 } 00616 00617 DCOPRef KMKernel::openComposer(const TQString &to, const TQString &cc, 00618 const TQString &bcc, const TQString &subject, 00619 const TQString &body,bool hidden) 00620 { 00621 KMMessage *msg = new KMMessage; 00622 msg->initHeader(); 00623 msg->setCharset("utf-8"); 00624 if (!cc.isEmpty()) msg->setCc(cc); 00625 if (!bcc.isEmpty()) msg->setBcc(bcc); 00626 if (!subject.isEmpty()) msg->setSubject(subject); 00627 if (!to.isEmpty()) msg->setTo(to); 00628 if (!body.isEmpty()) { 00629 msg->setBody(body.utf8()); 00630 } else { 00631 TemplateParser parser( msg, TemplateParser::NewMessage ); 00632 parser.process( NULL, NULL ); 00633 } 00634 00635 KMail::Composer * cWin = KMail::makeComposer( msg ); 00636 cWin->setCharset("", true); 00637 if (!hidden) { 00638 cWin->show(); 00639 // Activate window - doing this instead of KWin::activateWindow(cWin->winId()); 00640 // so that it also works when called from KMailApplication::newInstance() 00641 #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY 00642 KStartupInfo::setNewStartupId( cWin, kapp->startupId() ); 00643 #endif 00644 } 00645 00646 return DCOPRef( cWin->asMailComposerIFace() ); 00647 } 00648 00649 DCOPRef KMKernel::newMessage(const TQString &to, 00650 const TQString &cc, 00651 const TQString &bcc, 00652 bool hidden, 00653 bool useFolderId, 00654 const KURL & /*messageFile*/, 00655 const KURL &attachURL) 00656 { 00657 KMail::Composer * win = 0; 00658 KMMessage *msg = new KMMessage; 00659 KMFolder *folder = NULL; 00660 uint id; 00661 00662 if ( useFolderId ) { 00663 //create message with required folder identity 00664 folder = currentFolder(); 00665 id = folder ? folder->identity() : 0; 00666 msg->initHeader( id ); 00667 } else { 00668 msg->initHeader(); 00669 } 00670 msg->setCharset("utf-8"); 00671 //set basic headers 00672 if (!to.isEmpty()) msg->setTo(to); 00673 if (!cc.isEmpty()) msg->setCc(cc); 00674 if (!bcc.isEmpty()) msg->setBcc(bcc); 00675 00676 if ( useFolderId ) { 00677 TemplateParser parser( msg, TemplateParser::NewMessage ); 00678 parser.process( NULL, folder ); 00679 win = makeComposer( msg, id ); 00680 } else { 00681 TemplateParser parser( msg, TemplateParser::NewMessage ); 00682 parser.process( NULL, folder ); 00683 win = makeComposer( msg ); 00684 } 00685 00686 //Add the attachment if we have one 00687 if(!attachURL.isEmpty() && attachURL.isValid()) { 00688 win->addAttach(attachURL); 00689 } 00690 00691 //only show window when required 00692 if(!hidden) { 00693 win->show(); 00694 } 00695 return DCOPRef( win->asMailComposerIFace() ); 00696 } 00697 00698 int KMKernel::viewMessage( const KURL & messageFile ) 00699 { 00700 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( 0, messageFile ); 00701 00702 openCommand->start(); 00703 00704 return 1; 00705 } 00706 00707 int KMKernel::sendCertificate( const TQString& to, const TQByteArray& certData ) 00708 { 00709 KMMessage *msg = new KMMessage; 00710 msg->initHeader(); 00711 msg->setCharset("utf-8"); 00712 msg->setSubject( i18n( "Certificate Signature Request" ) ); 00713 if (!to.isEmpty()) msg->setTo(to); 00714 // ### Make this message customizable via KIOSK 00715 msg->setBody( i18n( "Please create a certificate from attachment and return to sender." ).utf8() ); 00716 00717 KMail::Composer * cWin = KMail::makeComposer( msg ); 00718 cWin->setCharset("", true); 00719 cWin->slotSetAlwaysSend( true ); 00720 if (!certData.isEmpty()) { 00721 KMMessagePart *msgPart = new KMMessagePart; 00722 msgPart->setName("smime.p10"); 00723 msgPart->setCteStr("base64"); 00724 msgPart->setBodyEncodedBinary(certData); 00725 msgPart->setTypeStr("application"); 00726 msgPart->setSubtypeStr("pkcs10"); 00727 msgPart->setContentDisposition("attachment; filename=smime.p10"); 00728 cWin->addAttach(msgPart); 00729 } 00730 00731 cWin->show(); 00732 return 1; 00733 } 00734 00735 KMMsgStatus KMKernel::strToStatus(const TQString &flags) 00736 { 00737 KMMsgStatus status = 0; 00738 if (!flags.isEmpty()) { 00739 for (uint n = 0; n < flags.length() ; n++) { 00740 switch (flags[n]) { 00741 case 'N': 00742 status |= KMMsgStatusNew; 00743 break; 00744 case 'U': 00745 status |= KMMsgStatusUnread; 00746 break; 00747 case 'O': 00748 status |= KMMsgStatusOld; 00749 break; 00750 case 'R': 00751 status |= KMMsgStatusRead; 00752 break; 00753 case 'D': 00754 status |= KMMsgStatusDeleted; 00755 break; 00756 case 'A': 00757 status |= KMMsgStatusReplied; 00758 break; 00759 case 'F': 00760 status |= KMMsgStatusForwarded; 00761 break; 00762 case 'Q': 00763 status |= KMMsgStatusQueued; 00764 break; 00765 case 'K': 00766 status |= KMMsgStatusTodo; 00767 break; 00768 case 'S': 00769 status |= KMMsgStatusSent; 00770 break; 00771 case 'G': 00772 status |= KMMsgStatusFlag; 00773 break; 00774 case 'W': 00775 status |= KMMsgStatusWatched; 00776 break; 00777 case 'I': 00778 status |= KMMsgStatusIgnored; 00779 break; 00780 case 'P': 00781 status |= KMMsgStatusSpam; 00782 break; 00783 case 'H': 00784 status |= KMMsgStatusHam; 00785 break; 00786 case 'T': 00787 status |= KMMsgStatusHasAttach; 00788 break; 00789 case 'C': 00790 status |= KMMsgStatusHasNoAttach; 00791 break; 00792 default: 00793 break; 00794 } 00795 } 00796 } 00797 return status; 00798 } 00799 00800 int KMKernel::dcopAddMessage( const TQString & foldername, const TQString & msgUrlString, 00801 const TQString & MsgStatusFlags) 00802 { 00803 return dcopAddMessage(foldername, KURL(msgUrlString), MsgStatusFlags); 00804 } 00805 00806 int KMKernel::dcopAddMessage( const TQString & foldername,const KURL & msgUrl, 00807 const TQString & MsgStatusFlags) 00808 { 00809 kdDebug(5006) << "KMKernel::dcopAddMessage called" << endl; 00810 00811 if ( foldername.isEmpty() || foldername.startsWith(".")) 00812 return -1; 00813 00814 int retval; 00815 bool readFolderMsgIds = false; 00816 TQString _foldername = foldername.stripWhiteSpace(); 00817 _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences 00818 00819 if ( foldername != mAddMessageLastFolder ) { 00820 mAddMessageMsgIds.clear(); 00821 readFolderMsgIds = true; 00822 mAddMessageLastFolder = foldername; 00823 } 00824 00825 if (!msgUrl.isEmpty() && msgUrl.isLocalFile()) { 00826 00827 // This is a proposed change by Daniel Andor. 00828 // He proposed to change from the fopen(blah) 00829 // to a KPIM::kFileToString(blah). 00830 // Although it assigns a TQString to a TQString, 00831 // because of the implicit sharing this poses 00832 // no memory or performance penalty. 00833 00834 const TQCString messageText = 00835 KPIM::kFileToString( msgUrl.path(), true, false ); 00836 if ( messageText.isEmpty() ) 00837 return -2; 00838 00839 KMMessage *msg = new KMMessage(); 00840 msg->fromString( messageText ); 00841 00842 if (readFolderMsgIds) { 00843 if ( foldername.contains("/")) { 00844 TQString tmp_fname = ""; 00845 KMFolder *folder = NULL; 00846 KMFolderDir *subfolder; 00847 bool root = true; 00848 00849 TQStringList subFList = TQStringList::split("/",_foldername,false); 00850 00851 for ( TQStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) { 00852 TQString _newFolder = *it; 00853 if(_newFolder.startsWith(".")) return -1; 00854 00855 if(root) { 00856 folder = the_folderMgr->findOrCreate(*it, false); 00857 if (folder) { 00858 root = false; 00859 tmp_fname = "/" + *it; 00860 } 00861 else return -1; 00862 } else { 00863 subfolder = folder->createChildFolder(); 00864 tmp_fname += "/" + *it; 00865 if(!the_folderMgr->getFolderByURL( tmp_fname )) { 00866 folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder); 00867 } 00868 00869 if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1; 00870 } 00871 } 00872 00873 mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname ); 00874 if(!folder) return -1; 00875 00876 } else { 00877 mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false); 00878 } 00879 } 00880 00881 if ( mAddMsgCurrentFolder ) { 00882 if (readFolderMsgIds) { 00883 00884 // OLD COMMENT: 00885 // Try to determine if a message already exists in 00886 // the folder. The message id that is searched for, is 00887 // the subject line + the date. This should be quite 00888 // unique. The change that a given date with a given 00889 // subject is in the folder twice is very small. 00890 // If the subject is empty, the fromStrip string 00891 // is taken. 00892 00893 // NEW COMMENT from Danny Kukawka (danny.kukawka@web.de): 00894 // subject line + the date is only unique if the following 00895 // return a correct unique value: 00896 // time_t DT = mb->date(); 00897 // TQString dt = ctime(&DT); 00898 // But if the datestring in the Header isn't RFC conform 00899 // subject line + the date isn't unique. 00900 // 00901 // The only uique headerfield is the Message-ID. In some 00902 // cases this could be empty. I then I use the 00903 // subject line + dateStr . 00904 00905 int i; 00906 00907 mAddMsgCurrentFolder->open("dcopadd"); 00908 for( i=0; i<mAddMsgCurrentFolder->count(); i++) { 00909 KMMsgBase *mb = mAddMsgCurrentFolder->getMsgBase(i); 00910 TQString id = mb->msgIdMD5(); 00911 if ( id.isEmpty() ) { 00912 id = mb->subject(); 00913 if ( id.isEmpty() ) 00914 id = mb->fromStrip(); 00915 if ( id.isEmpty() ) 00916 id = mb->toStrip(); 00917 00918 id += mb->dateStr(); 00919 } 00920 00921 //fprintf(stderr,"%s\n",(const char *) id); 00922 if ( !id.isEmpty() ) { 00923 mAddMessageMsgIds.append(id); 00924 } 00925 } 00926 mAddMsgCurrentFolder->close("dcopadd"); 00927 } 00928 00929 TQString msgId = msg->msgIdMD5(); 00930 if ( msgId.isEmpty()) { 00931 msgId = msg->subject(); 00932 if ( msgId.isEmpty() ) 00933 msgId = msg->fromStrip(); 00934 if ( msgId.isEmpty() ) 00935 msgId = msg->toStrip(); 00936 00937 msgId += msg->dateStr(); 00938 } 00939 00940 int k = mAddMessageMsgIds.findIndex( msgId ); 00941 //fprintf(stderr,"find %s = %d\n",(const char *) msgId,k); 00942 00943 if ( k == -1 ) { 00944 if ( !msgId.isEmpty() ) { 00945 mAddMessageMsgIds.append( msgId ); 00946 } 00947 00948 if ( !MsgStatusFlags.isEmpty() ) { 00949 KMMsgStatus status = strToStatus(MsgStatusFlags); 00950 if (status) msg->setStatus(status); 00951 } 00952 00953 int index; 00954 if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) { 00955 mAddMsgCurrentFolder->unGetMsg( index ); 00956 retval = 1; 00957 } else { 00958 retval =- 2; 00959 delete msg; 00960 msg = 0; 00961 } 00962 } else { 00963 //qDebug( "duplicate: " + msgId + "; subj: " + msg->subject() + ", from: " + msgId = msg->fromStrip()); 00964 retval = -4; 00965 } 00966 } else { 00967 retval = -1; 00968 } 00969 } else { 00970 retval = -2; 00971 } 00972 return retval; 00973 } 00974 00975 void KMKernel::dcopResetAddMessage() 00976 { 00977 mAddMessageMsgIds.clear(); 00978 mAddMessageLastFolder = TQString(); 00979 } 00980 00981 int KMKernel::dcopAddMessage_fastImport( const TQString & foldername, 00982 const TQString & msgUrlString, 00983 const TQString & MsgStatusFlags) 00984 { 00985 return dcopAddMessage_fastImport(foldername, KURL(msgUrlString), MsgStatusFlags); 00986 } 00987 00988 int KMKernel::dcopAddMessage_fastImport( const TQString & foldername, 00989 const KURL & msgUrl, 00990 const TQString & MsgStatusFlags) 00991 { 00992 // Use this function to import messages without 00993 // search for already existing emails. 00994 kdDebug(5006) << "KMKernel::dcopAddMessage_fastImport called" << endl; 00995 00996 if ( foldername.isEmpty() || foldername.startsWith(".")) 00997 return -1; 00998 00999 int retval; 01000 bool createNewFolder = false; 01001 01002 TQString _foldername = foldername.stripWhiteSpace(); 01003 _foldername = _foldername.replace('\\',""); //try to prevent ESCAPE Sequences 01004 01005 if ( foldername != mAddMessageLastFolder ) { 01006 createNewFolder = true; 01007 mAddMessageLastFolder = foldername; 01008 } 01009 01010 01011 if ( !msgUrl.isEmpty() && msgUrl.isLocalFile() ) { 01012 const TQCString messageText = 01013 KPIM::kFileToString( msgUrl.path(), true, false ); 01014 if ( messageText.isEmpty() ) 01015 return -2; 01016 01017 KMMessage *msg = new KMMessage(); 01018 msg->fromString( messageText ); 01019 01020 if (createNewFolder) { 01021 if ( foldername.contains("/")) { 01022 TQString tmp_fname = ""; 01023 KMFolder *folder = NULL; 01024 KMFolderDir *subfolder; 01025 bool root = true; 01026 01027 TQStringList subFList = TQStringList::split("/",_foldername,false); 01028 01029 for ( TQStringList::Iterator it = subFList.begin(); it != subFList.end(); ++it ) { 01030 TQString _newFolder = *it; 01031 if(_newFolder.startsWith(".")) return -1; 01032 01033 if(root) { 01034 folder = the_folderMgr->findOrCreate(*it, false); 01035 if (folder) { 01036 root = false; 01037 tmp_fname = "/" + *it; 01038 } 01039 else return -1; 01040 } else { 01041 subfolder = folder->createChildFolder(); 01042 tmp_fname += "/" + *it; 01043 if(!the_folderMgr->getFolderByURL( tmp_fname )) { 01044 folder = the_folderMgr->createFolder(*it, false, folder->folderType(), subfolder); 01045 } 01046 if(!(folder = the_folderMgr->getFolderByURL( tmp_fname ))) return -1; 01047 } 01048 } 01049 01050 mAddMsgCurrentFolder = the_folderMgr->getFolderByURL( tmp_fname ); 01051 if(!folder) return -1; 01052 01053 } else { 01054 mAddMsgCurrentFolder = the_folderMgr->findOrCreate(_foldername, false); 01055 } 01056 } 01057 01058 if ( mAddMsgCurrentFolder ) { 01059 int index; 01060 01061 if( !MsgStatusFlags.isEmpty() ) { 01062 KMMsgStatus status = strToStatus(MsgStatusFlags); 01063 if (status) msg->setStatus(status); 01064 } 01065 01066 if ( mAddMsgCurrentFolder->addMsg( msg, &index ) == 0 ) { 01067 mAddMsgCurrentFolder->unGetMsg( index ); 01068 retval = 1; 01069 } else { 01070 retval =- 2; 01071 delete msg; 01072 msg = 0; 01073 } 01074 } else { 01075 retval = -1; 01076 } 01077 } else { 01078 retval = -2; 01079 } 01080 01081 return retval; 01082 } 01083 01084 void KMKernel::showImportArchiveDialog() 01085 { 01086 KMMainWidget *mainWidget = getKMMainWidget(); 01087 KMail::ImportArchiveDialog *importDialog = new KMail::ImportArchiveDialog( mainWidget, WDestructiveClose ); 01088 importDialog->setFolder( mainWidget->folderTree()->currentFolder() ); 01089 importDialog->show(); 01090 } 01091 01092 TQStringList KMKernel::folderList() const 01093 { 01094 TQStringList folders; 01095 const TQString localPrefix = "/Local"; 01096 folders << localPrefix; 01097 the_folderMgr->getFolderURLS( folders, localPrefix ); 01098 the_imapFolderMgr->getFolderURLS( folders ); 01099 the_dimapFolderMgr->getFolderURLS( folders ); 01100 return folders; 01101 } 01102 01103 DCOPRef KMKernel::getFolder( const TQString& vpath ) 01104 { 01105 const TQString localPrefix = "/Local"; 01106 if ( the_folderMgr->getFolderByURL( vpath ) ) 01107 return DCOPRef( new FolderIface( vpath ) ); 01108 else if ( vpath.startsWith( localPrefix ) && 01109 the_folderMgr->getFolderByURL( vpath.mid( localPrefix.length() ) ) ) 01110 return DCOPRef( new FolderIface( vpath.mid( localPrefix.length() ) ) ); 01111 else if ( the_imapFolderMgr->getFolderByURL( vpath ) ) 01112 return DCOPRef( new FolderIface( vpath ) ); 01113 else if ( the_dimapFolderMgr->getFolderByURL( vpath ) ) 01114 return DCOPRef( new FolderIface( vpath ) ); 01115 return DCOPRef(); 01116 } 01117 01118 void KMKernel::raise() 01119 { 01120 DCOPRef kmail( "kmail", "kmail" ); 01121 kmail.call( "newInstance" ); 01122 } 01123 01124 bool KMKernel::showMail( TQ_UINT32 serialNumber, TQString /* messageId */ ) 01125 { 01126 KMMainWidget *mainWidget = 0; 01127 if (KMainWindow::memberList) { 01128 KMainWindow *win = 0; 01129 TQObjectList *l; 01130 01131 // First look for a KMainWindow. 01132 for (win = KMainWindow::memberList->first(); win; 01133 win = KMainWindow::memberList->next()) { 01134 // Then look for a KMMainWidget. 01135 l = win->queryList("KMMainWidget"); 01136 if (l && l->first()) { 01137 mainWidget = dynamic_cast<KMMainWidget *>(l->first()); 01138 if (win->isActiveWindow()) 01139 break; 01140 } 01141 } 01142 } 01143 01144 if (mainWidget) { 01145 int idx = -1; 01146 KMFolder *folder = 0; 01147 KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx); 01148 if (!folder || (idx == -1)) 01149 return false; 01150 KMFolderOpener openFolder(folder, "showmail"); 01151 KMMsgBase *msgBase = folder->getMsgBase(idx); 01152 if (!msgBase) 01153 return false; 01154 bool unGet = !msgBase->isMessage(); 01155 KMMessage *msg = folder->getMsg(idx); 01156 01157 KMReaderMainWin *win = new KMReaderMainWin( false, false ); 01158 KMMessage *newMessage = new KMMessage( *msg ); 01159 newMessage->setParent( msg->parent() ); 01160 newMessage->setMsgSerNum( msg->getMsgSerNum() ); 01161 newMessage->setReadyToShow( true ); 01162 win->showMsg( GlobalSettings::self()->overrideCharacterEncoding(), newMessage ); 01163 win->show(); 01164 01165 if (unGet) 01166 folder->unGetMsg(idx); 01167 return true; 01168 } 01169 01170 return false; 01171 } 01172 01173 TQString KMKernel::getFrom( TQ_UINT32 serialNumber ) 01174 { 01175 int idx = -1; 01176 KMFolder *folder = 0; 01177 KMMsgDict::instance()->getLocation(serialNumber, &folder, &idx); 01178 if (!folder || (idx == -1)) 01179 return TQString(); 01180 KMFolderOpener openFolder(folder, "getFrom"); 01181 KMMsgBase *msgBase = folder->getMsgBase(idx); 01182 if (!msgBase) 01183 return TQString(); 01184 bool unGet = !msgBase->isMessage(); 01185 KMMessage *msg = folder->getMsg(idx); 01186 TQString result = msg->from(); 01187 if (unGet) 01188 folder->unGetMsg(idx); 01189 return result; 01190 } 01191 01192 TQString KMKernel::debugScheduler() 01193 { 01194 TQString res = KMail::ActionScheduler::debug(); 01195 return res; 01196 } 01197 01198 TQString KMKernel::debugSernum( TQ_UINT32 serialNumber ) 01199 { 01200 TQString res; 01201 if (serialNumber != 0) { 01202 int idx = -1; 01203 KMFolder *folder = 0; 01204 KMMsgBase *msg = 0; 01205 KMMsgDict::instance()->getLocation( serialNumber, &folder, &idx ); 01206 // It's possible that the message has been deleted or moved into a 01207 // different folder 01208 if (folder && (idx != -1)) { 01209 // everything is ok 01210 KMFolderOpener openFolder(folder, "debugser"); 01211 msg = folder->getMsgBase( idx ); 01212 if (msg) { 01213 res.append( TQString( " subject %s,\n sender %s,\n date %s.\n" ) 01214 .arg( msg->subject() ) 01215 .arg( msg->fromStrip() ) 01216 .arg( msg->dateStr() ) ); 01217 } else { 01218 res.append( TQString( "Invalid serial number." ) ); 01219 } 01220 } else { 01221 res.append( TQString( "Invalid serial number." ) ); 01222 } 01223 } 01224 return res; 01225 } 01226 01227 01228 void KMKernel::pauseBackgroundJobs() 01229 { 01230 mBackgroundTasksTimer->stop(); 01231 mJobScheduler->pause(); 01232 } 01233 01234 void KMKernel::resumeBackgroundJobs() 01235 { 01236 mJobScheduler->resume(); 01237 mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); 01238 } 01239 01240 void KMKernel::stopNetworkJobs() 01241 { 01242 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline ) 01243 return; 01244 01245 GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Offline ); 01246 BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended")); 01247 emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() ); 01248 } 01249 01250 void KMKernel::resumeNetworkJobs() 01251 { 01252 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online ) 01253 return; 01254 01255 GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Online ); 01256 BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed")); 01257 emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() ); 01258 01259 if ( kmkernel->msgSender()->sendImmediate() ) { 01260 kmkernel->msgSender()->sendQueued(); 01261 } 01262 } 01263 01264 bool KMKernel::isOffline() 01265 { 01266 if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline ) 01267 return true; 01268 else 01269 return false; 01270 } 01271 01272 bool KMKernel::askToGoOnline() 01273 { 01274 // already asking means we are offline and need to wait anyhow 01275 if ( s_askingToGoOnline ) { 01276 return false; 01277 } 01278 01279 if ( kmkernel->isOffline() ) { 01280 s_askingToGoOnline = true; 01281 int rc = 01282 KMessageBox::questionYesNo( KMKernel::self()->mainWin(), 01283 i18n("KMail is currently in offline mode. " 01284 "How do you want to proceed?"), 01285 i18n("Online/Offline"), 01286 i18n("Work Online"), 01287 i18n("Work Offline")); 01288 01289 s_askingToGoOnline = false; 01290 if( rc == KMessageBox::No ) { 01291 return false; 01292 } else { 01293 kmkernel->resumeNetworkJobs(); 01294 } 01295 } 01296 return true; 01297 } 01298 01299 /********************************************************************/ 01300 /* Kernel methods */ 01301 /********************************************************************/ 01302 01303 void KMKernel::quit() 01304 { 01305 // Called when all windows are closed. Will take care of compacting, 01306 // sending... should handle session management too!! 01307 } 01308 /* TODO later: 01309 Asuming that: 01310 - msgsender is nonblocking 01311 (our own, TQSocketNotifier based. Pops up errors and sends signal 01312 senderFinished when done) 01313 01314 o If we are getting mail, stop it (but dont lose something!) 01315 [Done already, see mailCheckAborted] 01316 o If we are sending mail, go on UNLESS this was called by SM, 01317 in which case stop ASAP that too (can we warn? should we continue 01318 on next start?) 01319 o If we are compacting, or expunging, go on UNLESS this was SM call. 01320 In that case stop compacting ASAP and continue on next start, before 01321 touching any folders. [Not needed anymore with CompactionJob] 01322 01323 KMKernel::quit () 01324 { 01325 SM call? 01326 if compacting, stop; 01327 if sending, stop; 01328 if receiving, stop; 01329 Windows will take care of themselves (composer should dump 01330 its messages, if any but not in deadMail) 01331 declare us ready for the End of the Session 01332 01333 No, normal quit call 01334 All windows are off. Anything to do, should compact or sender sends? 01335 Yes, maybe put an icon in panel as a sign of life 01336 if sender sending, connect us to his finished slot, declare us ready 01337 for quit and wait for senderFinished 01338 if not, Folder manager, go compact sent-mail and outbox 01339 } (= call slotFinished()) 01340 01341 void KMKernel::slotSenderFinished() 01342 { 01343 good, Folder manager go compact sent-mail and outbox 01344 clean up stage1 (release folders and config, unregister from dcop) 01345 -- another kmail may start now --- 01346 kapp->quit(); 01347 } 01348 */ 01349 01350 01351 /********************************************************************/ 01352 /* Init, Exit, and handler methods */ 01353 /********************************************************************/ 01354 void KMKernel::testDir(const char *_name) 01355 { 01356 TQString foldersPath = TQDir::homeDirPath() + TQString( _name ); 01357 TQFileInfo info( foldersPath ); 01358 if ( !info.exists() ) { 01359 if ( ::mkdir( TQFile::encodeName( foldersPath ) , S_IRWXU ) == -1 ) { 01360 KMessageBox::sorry(0, i18n("KMail could not create folder '%1';\n" 01361 "please make sure that you can view and " 01362 "modify the content of the folder '%2'.") 01363 .arg( foldersPath ).arg( TQDir::homeDirPath() ) ); 01364 ::exit(-1); 01365 } 01366 } 01367 if ( !info.isDir() || !info.isReadable() || !info.isWritable() ) { 01368 KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are " 01369 "incorrect;\n" 01370 "please make sure that you can view and modify " 01371 "the content of this folder.") 01372 .arg( foldersPath ) ); 01373 ::exit(-1); 01374 } 01375 } 01376 01377 01378 //----------------------------------------------------------------------------- 01379 // Open a composer for each message found in the dead.letter folder 01380 void KMKernel::recoverDeadLetters() 01381 { 01382 TQDir dir( localDataPath() + "autosave/cur" ); 01383 if ( !dir.exists() ) { 01384 kdWarning(5006) << "Autosave directory " << dir.path() << " not found!" << endl; 01385 return; 01386 } 01387 01388 const TQStringList entryList = dir.entryList( TQDir::Files | TQDir::NoSymLinks, TQDir::Unsorted ); 01389 for ( unsigned int i = 0; i < entryList.size(); i++ ) { 01390 const TQString fileName = entryList[i]; 01391 TQFile file( dir.path() + '/' + fileName ); 01392 if ( !file.open( IO_ReadOnly ) ) { 01393 kdWarning(5006) << "Unable to open autosave file " << fileName << endl; 01394 continue; 01395 } 01396 const TQByteArray msgData = file.readAll(); 01397 file.close(); 01398 01399 if ( msgData.isEmpty() ) { 01400 kdWarning(5006) << "autosave file " << fileName << " is empty!" << endl; 01401 continue; 01402 } 01403 01404 KMMessage *msg = new KMMessage(); // Composer will take ownership 01405 msg->fromByteArray( msgData ); 01406 KMail::Composer * win = KMail::makeComposer(); 01407 win->setMsg( msg, false, false, true ); 01408 win->setAutoSaveFilename( fileName ); 01409 win->show(); 01410 } 01411 } 01412 01413 //----------------------------------------------------------------------------- 01414 void KMKernel::initFolders(KConfig* cfg) 01415 { 01416 TQString name; 01417 01418 name = cfg->readEntry("inboxFolder"); 01419 01420 // Currently the folder manager cannot manage folders which are not 01421 // in the base folder directory. 01422 //if (name.isEmpty()) name = getenv("MAIL"); 01423 01424 if (name.isEmpty()) name = I18N_NOOP("inbox"); 01425 01426 the_inboxFolder = (KMFolder*)the_folderMgr->findOrCreate(name); 01427 01428 if (the_inboxFolder->canAccess() != 0) { 01429 emergencyExit( i18n("You do not have read/write permission to your inbox folder.") ); 01430 } 01431 01432 the_inboxFolder->setSystemFolder(true); 01433 if ( the_inboxFolder->userWhoField().isEmpty() ) 01434 the_inboxFolder->setUserWhoField( TQString() ); 01435 // inboxFolder->open(); 01436 01437 the_outboxFolder = the_folderMgr->findOrCreate(cfg->readEntry("outboxFolder", I18N_NOOP("outbox"))); 01438 if (the_outboxFolder->canAccess() != 0) { 01439 emergencyExit( i18n("You do not have read/write permission to your outbox folder.") ); 01440 } 01441 the_outboxFolder->setNoChildren(true); 01442 01443 the_outboxFolder->setSystemFolder(true); 01444 if ( the_outboxFolder->userWhoField().isEmpty() ) 01445 the_outboxFolder->setUserWhoField( TQString() ); 01446 /* Nuke the oubox's index file, to make sure that no ghost messages are in 01447 * it from a previous crash. Ghost messages happen in the outbox because it 01448 * the only folder where messages enter and leave within 5 seconds, which is 01449 * the leniency period for index invalidation. Since the number of mails in 01450 * this folder is expected to be very small, we can live with regenerating 01451 * the index on each start to be on the save side. */ 01452 //if ( the_outboxFolder->folderType() == KMFolderTypeMaildir ) 01453 // unlink( TQFile::encodeName( the_outboxFolder->indexLocation() ) ); 01454 the_outboxFolder->open("kmkernel"); 01455 01456 the_sentFolder = the_folderMgr->findOrCreate(cfg->readEntry("sentFolder", I18N_NOOP("sent-mail"))); 01457 if (the_sentFolder->canAccess() != 0) { 01458 emergencyExit( i18n("You do not have read/write permission to your sent-mail folder.") ); 01459 } 01460 the_sentFolder->setSystemFolder(true); 01461 if ( the_sentFolder->userWhoField().isEmpty() ) 01462 the_sentFolder->setUserWhoField( TQString() ); 01463 // the_sentFolder->open(); 01464 01465 the_trashFolder = the_folderMgr->findOrCreate(cfg->readEntry("trashFolder", I18N_NOOP("trash"))); 01466 if (the_trashFolder->canAccess() != 0) { 01467 emergencyExit( i18n("You do not have read/write permission to your trash folder.") ); 01468 } 01469 the_trashFolder->setSystemFolder( true ); 01470 if ( the_trashFolder->userWhoField().isEmpty() ) 01471 the_trashFolder->setUserWhoField( TQString() ); 01472 // the_trashFolder->open(); 01473 01474 the_draftsFolder = the_folderMgr->findOrCreate(cfg->readEntry("draftsFolder", I18N_NOOP("drafts"))); 01475 if (the_draftsFolder->canAccess() != 0) { 01476 emergencyExit( i18n("You do not have read/write permission to your drafts folder.") ); 01477 } 01478 the_draftsFolder->setSystemFolder( true ); 01479 if ( the_draftsFolder->userWhoField().isEmpty() ) 01480 the_draftsFolder->setUserWhoField( TQString() ); 01481 the_draftsFolder->open("kmkernel"); 01482 01483 the_templatesFolder = 01484 the_folderMgr->findOrCreate( cfg->readEntry( "templatesFolder", 01485 I18N_NOOP("templates") ) ); 01486 if ( the_templatesFolder->canAccess() != 0 ) { 01487 emergencyExit( i18n("You do not have read/write permission to your templates folder.") ); 01488 } 01489 the_templatesFolder->setSystemFolder( true ); 01490 if ( the_templatesFolder->userWhoField().isEmpty() ) 01491 the_templatesFolder->setUserWhoField( TQString() ); 01492 the_templatesFolder->open("kmkernel"); 01493 } 01494 01495 01496 void KMKernel::init() 01497 { 01498 the_shuttingDown = false; 01499 the_server_is_ready = false; 01500 01501 KConfig* cfg = KMKernel::config(); 01502 01503 TQDir dir; 01504 01505 KConfigGroupSaver saver(cfg, "General"); 01506 the_firstStart = cfg->readBoolEntry("first-start", true); 01507 cfg->writeEntry("first-start", false); 01508 the_previousVersion = cfg->readEntry("previous-version"); 01509 cfg->writeEntry("previous-version", KMAIL_VERSION); 01510 TQString foldersPath = cfg->readPathEntry( "folders" ); 01511 kdDebug(5006) << k_funcinfo << "foldersPath (from config): '" << foldersPath << "'" << endl; 01512 01513 if ( foldersPath.isEmpty() ) { 01514 foldersPath = localDataPath() + "mail"; 01515 if ( transferMail( foldersPath ) ) { 01516 cfg->writePathEntry( "folders", foldersPath ); 01517 } 01518 kdDebug(5006) << k_funcinfo << "foldersPath (after transferMail): '" << foldersPath << "'" << endl; 01519 } 01520 01521 // moved up here because KMMessage::stripOffPrefixes is used below 01522 KMMessage::readConfig(); 01523 01524 the_undoStack = new UndoStack(20); 01525 the_folderMgr = new KMFolderMgr(foldersPath); 01526 the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir); 01527 the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir); 01528 recreateCorruptIndexFiles(); 01529 01530 the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir); 01531 KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") ); 01532 if (lsf) 01533 the_searchFolderMgr->remove( lsf ); 01534 01535 the_acctMgr = new AccountManager(); 01536 the_filterMgr = new KMFilterMgr(); 01537 the_popFilterMgr = new KMFilterMgr(true); 01538 the_filterActionDict = new KMFilterActionDict; 01539 01540 initFolders(cfg); 01541 the_acctMgr->readConfig(); 01542 the_filterMgr->readConfig(); 01543 the_popFilterMgr->readConfig(); 01544 cleanupImapFolders(); 01545 01546 the_msgSender = new KMSender; 01547 the_server_is_ready = true; 01548 imProxy()->initialize(); 01549 { // area for config group "Composer" 01550 KConfigGroupSaver saver(cfg, "Composer"); 01551 if (cfg->readListEntry("pref-charsets").isEmpty()) 01552 { 01553 cfg->writeEntry("pref-charsets", "us-ascii,iso-8859-1,locale,utf-8"); 01554 } 01555 } 01556 readConfig(); 01557 mICalIface->readConfig(); 01558 // filterMgr->dump(); 01559 #ifdef HAVE_INDEXLIB 01560 the_msgIndex = new KMMsgIndex(this); //create the indexer 01561 #else 01562 the_msgIndex = 0; 01563 #endif 01564 01565 //#if 0 01566 the_weaver = new KPIM::ThreadWeaver::Weaver( this ); 01567 the_weaverLogger = new KPIM::ThreadWeaver::WeaverThreadLogger(this); 01568 the_weaverLogger->attach (the_weaver); 01569 //#endif 01570 01571 connect( the_folderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ), 01572 this, TQT_SIGNAL( folderRemoved(KMFolder*) ) ); 01573 connect( the_dimapFolderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ), 01574 this, TQT_SIGNAL( folderRemoved(KMFolder*) ) ); 01575 connect( the_imapFolderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ), 01576 this, TQT_SIGNAL( folderRemoved(KMFolder*) ) ); 01577 connect( the_searchFolderMgr, TQT_SIGNAL( folderRemoved(KMFolder*) ), 01578 this, TQT_SIGNAL( folderRemoved(KMFolder*) ) ); 01579 01580 mBackgroundTasksTimer = new TQTimer( this, "mBackgroundTasksTimer" ); 01581 connect( mBackgroundTasksTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotRunBackgroundTasks() ) ); 01582 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h 01583 mBackgroundTasksTimer->start( 10000, true ); // 10s, singleshot 01584 #else 01585 mBackgroundTasksTimer->start( 5 * 60000, true ); // 5 minutes, singleshot 01586 #endif 01587 01588 TQTextCodec *codec; 01589 for ( int i = 0; ( codec = TQTextCodec::codecForIndex ( i ) ); i++ ) { 01590 const TQString asciiString( "azAZ19,.-#+!?=()&" ); 01591 const TQCString encodedString = codec->fromUnicode( asciiString ); 01592 if ( TQString::fromAscii( encodedString ) != asciiString ) { 01593 mNonAsciiCompatibleCodecs.append( codec ); 01594 } 01595 } 01596 } 01597 01598 bool KMKernel::isCodecAsciiCompatible( const TQTextCodec *codec ) 01599 { 01600 return !mNonAsciiCompatibleCodecs.contains( codec ); 01601 } 01602 01603 void KMKernel::readConfig() 01604 { 01605 //Needed here, since this function is also called when the configuration 01606 //changes, and the static variables should be updated then - IOF 01607 KMMessage::readConfig(); 01608 } 01609 01610 void KMKernel::cleanupImapFolders() 01611 { 01612 KMAccount *acct = 0; 01613 KMFolderNode *node = the_imapFolderMgr->dir().first(); 01614 while (node) 01615 { 01616 if (node->isDir() || ((acct = the_acctMgr->find(node->id())) 01617 && ( acct->type() == "imap" )) ) 01618 { 01619 node = the_imapFolderMgr->dir().next(); 01620 } else { 01621 KMFolder* folder = static_cast<KMFolder*>(node); 01622 // delete only local 01623 static_cast<KMFolderImap*>( folder->storage() )->setAlreadyRemoved( true ); 01624 the_imapFolderMgr->remove(folder); 01625 node = the_imapFolderMgr->dir().first(); 01626 } 01627 } 01628 01629 node = the_dimapFolderMgr->dir().first(); 01630 while (node) 01631 { 01632 if (node->isDir() || ((acct = the_acctMgr->find(node->id())) 01633 && ( acct->type() == "cachedimap" )) ) 01634 { 01635 node = the_dimapFolderMgr->dir().next(); 01636 } else { 01637 the_dimapFolderMgr->remove(static_cast<KMFolder*>(node)); 01638 node = the_dimapFolderMgr->dir().first(); 01639 } 01640 } 01641 01642 the_imapFolderMgr->quiet(true); 01643 for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next()) 01644 { 01645 KMFolderImap *fld; 01646 KMAcctImap *imapAcct; 01647 01648 if (acct->type() != "imap") continue; 01649 fld = static_cast<KMFolderImap*>(the_imapFolderMgr 01650 ->findOrCreate(TQString::number(acct->id()), false, acct->id())->storage()); 01651 fld->setNoContent(true); 01652 fld->folder()->setLabel(acct->name()); 01653 imapAcct = static_cast<KMAcctImap*>(acct); 01654 fld->setAccount(imapAcct); 01655 imapAcct->setImapFolder(fld); 01656 fld->close( "kernel", true ); 01657 } 01658 the_imapFolderMgr->quiet(false); 01659 01660 the_dimapFolderMgr->quiet( true ); 01661 for (acct = the_acctMgr->first(); acct; acct = the_acctMgr->next()) 01662 { 01663 KMFolderCachedImap *cfld = 0; 01664 KMAcctCachedImap *cachedImapAcct; 01665 01666 if (acct->type() != "cachedimap" ) continue; 01667 01668 KMFolder* fld = the_dimapFolderMgr->find(TQString::number(acct->id())); 01669 if( fld ) 01670 cfld = static_cast<KMFolderCachedImap*>( fld->storage() ); 01671 if (cfld == 0) { 01672 // Folder doesn't exist yet 01673 cfld = static_cast<KMFolderCachedImap*>(the_dimapFolderMgr->createFolder(TQString::number(acct->id()), 01674 false, KMFolderTypeCachedImap)->storage()); 01675 if (!cfld) { 01676 KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(acct->name()).arg(the_dimapFolderMgr->basePath()))); 01677 exit(-1); 01678 } 01679 cfld->folder()->setId( acct->id() ); 01680 } 01681 01682 cfld->setNoContent(true); 01683 cfld->folder()->setLabel(acct->name()); 01684 cachedImapAcct = static_cast<KMAcctCachedImap*>(acct); 01685 cfld->setAccount(cachedImapAcct); 01686 cachedImapAcct->setImapFolder(cfld); 01687 cfld->close("kmkernel"); 01688 } 01689 the_dimapFolderMgr->quiet( false ); 01690 } 01691 01692 void KMKernel::recreateCorruptIndexFiles() 01693 { 01694 TQValueList<TQGuardedPtr<KMFolder> > folders; 01695 TQValueList<KMFolderIndex*> foldersWithBrokenIndex; 01696 TQStringList strList; 01697 the_folderMgr->createFolderList( &strList, &folders ); 01698 the_imapFolderMgr->createFolderList( &strList, &folders ); 01699 the_dimapFolderMgr->createFolderList( &strList, &folders ); 01700 for ( int i = 0; folders.at(i) != folders.end(); i++ ) { 01701 KMFolder * const folder = *folders.at(i); 01702 if ( !folder || folder->isDir() || folder->isOpened() ) 01703 continue; 01704 KMFolderIndex * const index = dynamic_cast<KMFolderIndex*>( folder->storage() ); 01705 if ( index && index->indexStatus() != KMFolderIndex::IndexOk ) { 01706 foldersWithBrokenIndex.append( index ); 01707 } 01708 } 01709 01710 if ( !foldersWithBrokenIndex.isEmpty() ) { 01711 TQStringList folderNames; 01712 for ( uint i = 0; i < foldersWithBrokenIndex.size(); i++ ) { 01713 folderNames << foldersWithBrokenIndex[i]->label(); 01714 } 01715 01716 KMessageBox::informationList( 0, i18n( "There is a problem with the mail index of the following " 01717 "folders, the indices will now be regenerated.\n" 01718 "This can happen because the index files are out of date, missing or corrupted.\n" 01719 "Contact your administrator if this happens frequently.\n" 01720 "Some information, like status flags, might get lost." ), 01721 folderNames, i18n( "Problem with mail indices" ) ); 01722 01723 for ( uint i = 0; i < foldersWithBrokenIndex.size(); i++ ) { 01724 foldersWithBrokenIndex[i]->silentlyRecreateIndex(); 01725 } 01726 } 01727 } 01728 01729 bool KMKernel::doSessionManagement() 01730 { 01731 01732 // Do session management 01733 if (kapp->isRestored()){ 01734 int n = 1; 01735 while (KMMainWin::canBeRestored(n)){ 01736 //only restore main windows! (Matthias); 01737 if (KMMainWin::classNameOfToplevel(n) == "KMMainWin") 01738 (new KMMainWin)->restore(n); 01739 n++; 01740 } 01741 return true; // we were restored by SM 01742 } 01743 return false; // no, we were not restored 01744 } 01745 01746 void KMKernel::closeAllKMailWindows() 01747 { 01748 if (!KMainWindow::memberList) return; 01749 TQPtrListIterator<KMainWindow> it(*KMainWindow::memberList); 01750 KMainWindow *window = 0; 01751 while ((window = it.current()) != 0) { 01752 ++it; 01753 if (window->isA("KMMainWindow") || 01754 window->inherits("KMail::SecondaryWindow")) 01755 window->close( true ); // close and delete the window 01756 } 01757 } 01758 01759 void KMKernel::cleanup(void) 01760 { 01761 dumpDeadLetters(); 01762 the_shuttingDown = true; 01763 closeAllKMailWindows(); 01764 01765 delete the_acctMgr; 01766 the_acctMgr = 0; 01767 delete the_filterMgr; 01768 the_filterMgr = 0; 01769 delete the_msgSender; 01770 the_msgSender = 0; 01771 delete the_filterActionDict; 01772 the_filterActionDict = 0; 01773 delete the_undoStack; 01774 the_undoStack = 0; 01775 delete the_popFilterMgr; 01776 the_popFilterMgr = 0; 01777 01778 #if 0 01779 delete the_weaver; 01780 the_weaver = 0; 01781 #endif 01782 01783 KConfig* config = KMKernel::config(); 01784 KConfigGroupSaver saver(config, "General"); 01785 01786 if (the_trashFolder) { 01787 01788 the_trashFolder->close("kmkernel", true); 01789 01790 if (config->readBoolEntry("empty-trash-on-exit", true)) 01791 { 01792 if ( the_trashFolder->count( true ) > 0 ) 01793 the_trashFolder->expunge(); 01794 } 01795 } 01796 01797 mICalIface->cleanup(); 01798 01799 TQValueList<TQGuardedPtr<KMFolder> > folders; 01800 TQStringList strList; 01801 KMFolder *folder; 01802 the_folderMgr->createFolderList(&strList, &folders); 01803 for (int i = 0; folders.at(i) != folders.end(); i++) 01804 { 01805 folder = *folders.at(i); 01806 if (!folder || folder->isDir()) continue; 01807 folder->close("kmkernel", true); 01808 } 01809 strList.clear(); 01810 folders.clear(); 01811 the_searchFolderMgr->createFolderList(&strList, &folders); 01812 for (int i = 0; folders.at(i) != folders.end(); i++) 01813 { 01814 folder = *folders.at(i); 01815 if (!folder || folder->isDir()) continue; 01816 folder->close("kmkernel", true); 01817 } 01818 01819 delete the_msgIndex; 01820 the_msgIndex = 0; 01821 delete the_folderMgr; 01822 the_folderMgr = 0; 01823 delete the_imapFolderMgr; 01824 the_imapFolderMgr = 0; 01825 delete the_dimapFolderMgr; 01826 the_dimapFolderMgr = 0; 01827 delete the_searchFolderMgr; 01828 the_searchFolderMgr = 0; 01829 delete mConfigureDialog; 01830 mConfigureDialog = 0; 01831 // do not delete, because mWin may point to an existing window 01832 // delete mWin; 01833 mWin = 0; 01834 01835 if ( RecentAddresses::exists() ) 01836 RecentAddresses::self( config )->save( config ); 01837 config->sync(); 01838 } 01839 01840 bool KMKernel::transferMail( TQString & destinationDir ) 01841 { 01842 TQString dir; 01843 01844 // check whether the user has a ~/KMail folder 01845 TQFileInfo fi( TQDir::home(), "KMail" ); 01846 if ( fi.exists() && fi.isDir() ) { 01847 dir = TQDir::homeDirPath() + "/KMail"; 01848 // the following two lines can be removed once moving mail is reactivated 01849 destinationDir = dir; 01850 return true; 01851 } 01852 01853 if ( dir.isEmpty() ) { 01854 // check whether the user has a ~/Mail folder 01855 fi.setFile( TQDir::home(), "Mail" ); 01856 if ( fi.exists() && fi.isDir() && 01857 TQFile::exists( TQDir::homeDirPath() + "/Mail/.inbox.index" ) ) { 01858 // there's a ~/Mail folder which seems to be used by KMail (because of the 01859 // index file) 01860 dir = TQDir::homeDirPath() + "/Mail"; 01861 // the following two lines can be removed once moving mail is reactivated 01862 destinationDir = dir; 01863 return true; 01864 } 01865 } 01866 01867 if ( dir.isEmpty() ) { 01868 return true; // there's no old mail folder 01869 } 01870 01871 #if 0 01872 // disabled for now since moving fails in certain cases (e.g. if symbolic links are involved) 01873 const TQString kmailName = kapp->aboutData()->programName(); 01874 TQString msg; 01875 if ( KIO::NetAccess::exists( destinationDir, true, 0 ) ) { 01876 // if destinationDir exists, we need to warn about possible 01877 // overwriting of files. otherwise, we don't have to 01878 msg = i18n( "%1-%3 is the application name, %4-%7 are folder path", 01879 "<qt>The <i>%4</i> folder exists. " 01880 "%1 now uses the <i>%5</i> folder for " 01881 "its messages.<p>" 01882 "%2 can move the contents of <i>%6<i> into this folder for " 01883 "you, though this may replace any existing files with " 01884 "the same name in <i>%7</i>.<p>" 01885 "<strong>Would you like %3 to move the mail " 01886 "files now?</strong></qt>" ) 01887 .arg( kmailName, kmailName, kmailName ) 01888 .arg( dir, destinationDir, dir, destinationDir ); 01889 } else { 01890 msg = i18n( "%1-%3 is the application name, %4-%6 are folder path", 01891 "<qt>The <i>%4</i> folder exists. " 01892 "%1 now uses the <i>%5</i> folder for " 01893 "its messages. %2 can move the contents of <i>%6</i> into " 01894 "this folder for you.<p>" 01895 "<strong>Would you like %3 to move the mail " 01896 "files now?</strong></qt>" ) 01897 .arg( kmailName, kmailName, kmailName ) 01898 .arg( dir, destinationDir, dir ); 01899 } 01900 TQString title = i18n( "Migrate Mail Files?" ); 01901 TQString buttonText = i18n( "Move" ); 01902 01903 if ( KMessageBox::questionYesNo( 0, msg, title, buttonText, i18n("Do Not Move") ) == 01904 KMessageBox::No ) { 01905 destinationDir = dir; 01906 return true; 01907 } 01908 01909 if ( !KIO::NetAccess::move( dir, destinationDir ) ) { 01910 kdDebug(5006) << k_funcinfo << "Moving " << dir << " to " << destinationDir << " failed: " << KIO::NetAccess::lastErrorString() << endl; 01911 kdDebug(5006) << k_funcinfo << "Deleting " << destinationDir << endl; 01912 KIO::NetAccess::del( destinationDir, 0 ); 01913 destinationDir = dir; 01914 return false; 01915 } 01916 #endif 01917 01918 return true; 01919 } 01920 01921 01922 void KMKernel::ungrabPtrKb(void) 01923 { 01924 if(!KMainWindow::memberList) return; 01925 TQWidget* widg = KMainWindow::memberList->first(); 01926 Display* dpy; 01927 01928 if (!widg) return; 01929 dpy = widg->x11Display(); 01930 XUngrabKeyboard(dpy, CurrentTime); 01931 XUngrabPointer(dpy, CurrentTime); 01932 } 01933 01934 01935 // Message handler 01936 void KMKernel::kmailMsgHandler(TQtMsgType aType, const char* aMsg) 01937 { 01938 static int recurse=-1; 01939 01940 recurse++; 01941 01942 switch (aType) 01943 { 01944 case QtDebugMsg: 01945 case QtWarningMsg: 01946 kdDebug(5006) << aMsg << endl; 01947 break; 01948 01949 case QtFatalMsg: // Hm, what about using kdFatal() here? 01950 ungrabPtrKb(); 01951 kdDebug(5006) << kapp->caption() << " fatal error " 01952 << aMsg << endl; 01953 KMessageBox::error(0, aMsg); 01954 abort(); 01955 } 01956 01957 recurse--; 01958 } 01959 01960 01961 void KMKernel::dumpDeadLetters() 01962 { 01963 if ( shuttingDown() ) 01964 return; //All documents should be saved before shutting down is set! 01965 01966 // make all composer windows autosave their contents 01967 if ( !KMainWindow::memberList ) 01968 return; 01969 01970 for ( TQPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it ) { 01971 if ( KMail::Composer * win = ::tqqt_cast<KMail::Composer*>( it.current() ) ) { 01972 win->autoSaveMessage(); 01973 // saving the message has to be finished right here, we are called from a dtor, 01974 // therefore we have no chance to finish this later 01975 // yes, this is ugly and potentially dangerous, but the alternative is losing 01976 // currently composed messages... 01977 while ( win->isComposing() ) 01978 tqApp->processEvents(); 01979 } 01980 } 01981 } 01982 01983 01984 01985 void KMKernel::action(bool mailto, bool check, const TQString &to, 01986 const TQString &cc, const TQString &bcc, 01987 const TQString &subj, const TQString &body, 01988 const KURL &messageFile, 01989 const KURL::List &attachURLs, 01990 const QCStringList &customHeaders) 01991 { 01992 if ( mailto ) 01993 openComposer( to, cc, bcc, subj, body, 0, messageFile, attachURLs, customHeaders ); 01994 else 01995 openReader( check ); 01996 01997 if ( check ) 01998 checkMail(); 01999 //Anything else? 02000 } 02001 02002 void KMKernel::byteArrayToRemoteFile(const TQByteArray &aData, const KURL &aURL, 02003 bool overwrite) 02004 { 02005 // ## when KDE 3.3 is out: use KIO::storedPut to remove slotDataReq altogether 02006 KIO::Job *job = KIO::put(aURL, -1, overwrite, false); 02007 putData pd; pd.url = aURL; pd.data = aData; pd.offset = 0; 02008 mPutJobs.insert(job, pd); 02009 connect(job, TQT_SIGNAL(dataReq(KIO::Job*,TQByteArray&)), 02010 TQT_SLOT(slotDataReq(KIO::Job*,TQByteArray&))); 02011 connect(job, TQT_SIGNAL(result(KIO::Job*)), 02012 TQT_SLOT(slotResult(KIO::Job*))); 02013 } 02014 02015 void KMKernel::slotDataReq(KIO::Job *job, TQByteArray &data) 02016 { 02017 // send the data in 64 KB chunks 02018 const int MAX_CHUNK_SIZE = 64*1024; 02019 TQMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job); 02020 assert(it != mPutJobs.end()); 02021 int remainingBytes = (*it).data.size() - (*it).offset; 02022 if( remainingBytes > MAX_CHUNK_SIZE ) 02023 { 02024 // send MAX_CHUNK_SIZE bytes to the receiver (deep copy) 02025 data.duplicate( (*it).data.data() + (*it).offset, MAX_CHUNK_SIZE ); 02026 (*it).offset += MAX_CHUNK_SIZE; 02027 //kdDebug( 5006 ) << "Sending " << MAX_CHUNK_SIZE << " bytes (" 02028 // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n"; 02029 } 02030 else 02031 { 02032 // send the remaining bytes to the receiver (deep copy) 02033 data.duplicate( (*it).data.data() + (*it).offset, remainingBytes ); 02034 (*it).data = TQByteArray(); 02035 (*it).offset = 0; 02036 //kdDebug( 5006 ) << "Sending " << remainingBytes << " bytes\n"; 02037 } 02038 } 02039 02040 void KMKernel::slotResult(KIO::Job *job) 02041 { 02042 TQMap<KIO::Job*, putData>::Iterator it = mPutJobs.find(job); 02043 assert(it != mPutJobs.end()); 02044 if (job->error()) 02045 { 02046 if (job->error() == KIO::ERR_FILE_ALREADY_EXIST) 02047 { 02048 if (KMessageBox::warningContinueCancel(0, 02049 i18n("File %1 exists.\nDo you want to replace it?") 02050 .arg((*it).url.prettyURL()), i18n("Save to File"), i18n("&Replace")) 02051 == KMessageBox::Continue) 02052 byteArrayToRemoteFile((*it).data, (*it).url, true); 02053 } 02054 else job->showErrorDialog(); 02055 } 02056 mPutJobs.remove(it); 02057 } 02058 02059 void KMKernel::slotRequestConfigSync() { 02060 // ### FIXME: delay as promised in the kdoc of this function ;-) 02061 KMKernel::config()->sync(); 02062 } 02063 02064 void KMKernel::slotShowConfigurationDialog() 02065 { 02066 if( !mConfigureDialog ) { 02067 mConfigureDialog = new ConfigureDialog( 0, "configure", false ); 02068 connect( mConfigureDialog, TQT_SIGNAL( configChanged() ), 02069 this, TQT_SLOT( slotConfigChanged() ) ); 02070 } 02071 02072 if( KMKernel::getKMMainWidget() == 0 ) 02073 { 02074 // ensure that there is a main widget available 02075 // as parts of the configure dialog (identity) rely on this 02076 // and this slot can be called when there is only a KMComposeWin showing 02077 KMMainWin * win = new KMMainWin; 02078 win->show(); 02079 } 02080 if( mConfigureDialog->isHidden() ) 02081 { 02082 getKMMainWidget()->headers()->writeConfig(); 02083 mConfigureDialog->show(); 02084 } 02085 else 02086 mConfigureDialog->raise(); 02087 } 02088 02089 void KMKernel::slotConfigChanged() 02090 { 02091 readConfig(); 02092 emit configChanged(); 02093 } 02094 02095 //------------------------------------------------------------------------------- 02096 //static 02097 TQString KMKernel::localDataPath() 02098 { 02099 return locateLocal( "data", "kmail/" ); 02100 } 02101 02102 //------------------------------------------------------------------------------- 02103 02104 bool KMKernel::haveSystemTrayApplet() 02105 { 02106 return !systemTrayApplets.isEmpty(); 02107 } 02108 02109 bool KMKernel::registerSystemTrayApplet( const KSystemTray* applet ) 02110 { 02111 if ( systemTrayApplets.findIndex( applet ) == -1 ) { 02112 systemTrayApplets.append( applet ); 02113 return true; 02114 } 02115 else 02116 return false; 02117 } 02118 02119 bool KMKernel::unregisterSystemTrayApplet( const KSystemTray* applet ) 02120 { 02121 TQValueList<const KSystemTray*>::iterator it = 02122 systemTrayApplets.find( applet ); 02123 if ( it != systemTrayApplets.end() ) { 02124 systemTrayApplets.remove( it ); 02125 return true; 02126 } 02127 else 02128 return false; 02129 } 02130 02131 void KMKernel::emergencyExit( const TQString& reason ) 02132 { 02133 TQString mesg; 02134 if ( reason.length() == 0 ) { 02135 mesg = i18n("KMail encountered a fatal error and will terminate now"); 02136 } else { 02137 mesg = i18n("KMail encountered a fatal error and will " 02138 "terminate now.\nThe error was:\n%1").arg( reason ); 02139 } 02140 02141 kdWarning() << mesg << endl; 02142 KNotifyClient::userEvent( 0, "<qt>"+mesg+"</qt>", KNotifyClient::Messagebox, KNotifyClient::Error ); 02143 02144 ::exit(1); 02145 } 02146 02150 bool KMKernel::folderIsDraftOrOutbox(const KMFolder * folder) 02151 { 02152 assert( folder ); 02153 if ( folder == the_outboxFolder ) 02154 return true; 02155 return folderIsDrafts( folder ); 02156 } 02157 02158 bool KMKernel::folderIsDrafts(const KMFolder * folder) 02159 { 02160 assert( folder ); 02161 if ( folder == the_draftsFolder ) 02162 return true; 02163 02164 TQString idString = folder->idString(); 02165 if ( idString.isEmpty() ) 02166 return false; 02167 02168 // search the identities if the folder matches the drafts-folder 02169 const KPIM::IdentityManager *im = identityManager(); 02170 for ( KPIM::IdentityManager::ConstIterator it=im->begin(); it != im->end(); ++it ) 02171 if ( (*it).drafts() == idString ) 02172 return true; 02173 return false; 02174 } 02175 02176 bool KMKernel::folderIsTemplates( const KMFolder *folder ) 02177 { 02178 assert( folder ); 02179 if ( folder == the_templatesFolder ) 02180 return true; 02181 02182 TQString idString = folder->idString(); 02183 if ( idString.isEmpty() ) 02184 return false; 02185 02186 // search the identities if the folder matches the templates-folder 02187 const KPIM::IdentityManager *im = identityManager(); 02188 for ( KPIM::IdentityManager::ConstIterator it=im->begin(); it != im->end(); ++it ) 02189 if ( (*it).templates() == idString ) 02190 return true; 02191 return false; 02192 } 02193 02194 bool KMKernel::folderIsTrash(KMFolder * folder) 02195 { 02196 assert(folder); 02197 if (folder == the_trashFolder) return true; 02198 TQStringList actList = acctMgr()->getAccounts(); 02199 TQStringList::Iterator it( actList.begin() ); 02200 for( ; it != actList.end() ; ++it ) { 02201 KMAccount* act = acctMgr()->findByName( *it ); 02202 if ( act && ( act->trash() == folder->idString() ) ) 02203 return true; 02204 } 02205 return false; 02206 } 02207 02208 bool KMKernel::folderIsSentMailFolder( const KMFolder * folder ) 02209 { 02210 assert( folder ); 02211 if ( folder == the_sentFolder ) 02212 return true; 02213 02214 TQString idString = folder->idString(); 02215 if ( idString.isEmpty() ) return false; 02216 02217 // search the identities if the folder matches the sent-folder 02218 const KPIM::IdentityManager * im = identityManager(); 02219 for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it ) 02220 if ( (*it).fcc() == idString ) return true; 02221 return false; 02222 } 02223 02224 KPIM::IdentityManager * KMKernel::identityManager() { 02225 if ( !mIdentityManager ) { 02226 kdDebug(5006) << "instantating KPIM::IdentityManager" << endl; 02227 mIdentityManager = new KPIM::IdentityManager( false, this, "mIdentityManager" ); 02228 } 02229 return mIdentityManager; 02230 } 02231 02232 KMMsgIndex *KMKernel::msgIndex() 02233 { 02234 return the_msgIndex; 02235 } 02236 02237 KMainWindow* KMKernel::mainWin() 02238 { 02239 if (KMainWindow::memberList) { 02240 KMainWindow *kmWin = 0; 02241 02242 // First look for a KMMainWin. 02243 for (kmWin = KMainWindow::memberList->first(); kmWin; 02244 kmWin = KMainWindow::memberList->next()) 02245 if (kmWin->isA("KMMainWin")) 02246 return kmWin; 02247 02248 // There is no KMMainWin. Use any other KMainWindow instead (e.g. in 02249 // case we are running inside Kontact) because we anyway only need 02250 // it for modal message boxes and for KNotify events. 02251 kmWin = KMainWindow::memberList->first(); 02252 if ( kmWin ) 02253 return kmWin; 02254 } 02255 02256 // There's not a single KMainWindow. Create a KMMainWin. 02257 // This could happen if we want to pop up an error message 02258 // while we are still doing the startup wizard and no other 02259 // KMainWindow is running. 02260 mWin = new KMMainWin; 02261 return mWin; 02262 } 02263 02264 02268 void KMKernel::slotEmptyTrash() 02269 { 02270 TQString title = i18n("Empty Trash"); 02271 TQString text = i18n("Are you sure you want to empty the trash folders of all accounts?"); 02272 if (KMessageBox::warningContinueCancel(0, text, title, 02273 KStdGuiItem::cont(), "confirm_empty_trash") 02274 != KMessageBox::Continue) 02275 { 02276 return; 02277 } 02278 02279 for (KMAccount* acct = acctMgr()->first(); acct; acct = acctMgr()->next()) 02280 { 02281 KMFolder* trash = findFolderById(acct->trash()); 02282 if (trash) 02283 { 02284 trash->expunge(); 02285 } 02286 } 02287 } 02288 02289 KConfig* KMKernel::config() 02290 { 02291 assert(mySelf); 02292 if (!mySelf->mConfig) 02293 { 02294 mySelf->mConfig = KSharedConfig::openConfig( "kmailrc" ); 02295 // Check that all updates have been run on the config file: 02296 KMail::checkConfigUpdates(); 02297 } 02298 return mySelf->mConfig; 02299 } 02300 02301 KMailICalIfaceImpl& KMKernel::iCalIface() 02302 { 02303 assert( mICalIface ); 02304 return *mICalIface; 02305 } 02306 02307 void KMKernel::selectFolder( TQString folderPath ) 02308 { 02309 kdDebug(5006)<<"Selecting a folder "<<folderPath<<endl; 02310 const TQString localPrefix = "/Local"; 02311 KMFolder *folder = kmkernel->folderMgr()->getFolderByURL( folderPath ); 02312 if ( !folder && folderPath.startsWith( localPrefix ) ) 02313 folder = the_folderMgr->getFolderByURL( folderPath.mid( localPrefix.length() ) ); 02314 if ( !folder ) 02315 folder = kmkernel->imapFolderMgr()->getFolderByURL( folderPath ); 02316 if ( !folder ) 02317 folder = kmkernel->dimapFolderMgr()->getFolderByURL( folderPath ); 02318 Q_ASSERT( folder ); 02319 02320 KMMainWidget *widget = getKMMainWidget(); 02321 Q_ASSERT( widget ); 02322 if ( !widget ) 02323 return; 02324 02325 KMFolderTree *tree = widget->folderTree(); 02326 tree->doFolderSelected( tree->indexOfFolder( folder ) ); 02327 tree->ensureItemVisible( tree->indexOfFolder( folder ) ); 02328 } 02329 02330 KMMainWidget *KMKernel::getKMMainWidget() 02331 { 02332 //This could definitely use a speadup 02333 TQWidgetList *l = kapp->topLevelWidgets(); 02334 TQWidgetListIt it( *l ); 02335 TQWidget *wid; 02336 02337 while ( ( wid = it.current() ) != 0 ) { 02338 ++it; 02339 TQObjectList *l2 = wid->topLevelWidget()->queryList( "KMMainWidget" ); 02340 if (l2 && l2->first()) { 02341 KMMainWidget* kmmw = dynamic_cast<KMMainWidget *>( l2->first() ); 02342 Q_ASSERT( kmmw ); 02343 delete l2; 02344 delete l; 02345 return kmmw; 02346 } 02347 delete l2; 02348 } 02349 delete l; 02350 return 0; 02351 } 02352 02353 void KMKernel::slotRunBackgroundTasks() // called regularly by timer 02354 { 02355 // Hidden KConfig keys. Not meant to be used, but a nice fallback in case 02356 // a stable kmail release goes out with a nasty bug in CompactionJob... 02357 KConfigGroup generalGroup( config(), "General" ); 02358 02359 if ( generalGroup.readBoolEntry( "auto-expiring", true ) ) { 02360 the_folderMgr->expireAllFolders( false /*scheduled, not immediate*/ ); 02361 the_imapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ ); 02362 the_dimapFolderMgr->expireAllFolders( false /*scheduled, not immediate*/ ); 02363 // the_searchFolderMgr: no expiry there 02364 } 02365 02366 if ( generalGroup.readBoolEntry( "auto-compaction", true ) ) { 02367 the_folderMgr->compactAllFolders( false /*scheduled, not immediate*/ ); 02368 // the_imapFolderMgr: no compaction 02369 the_dimapFolderMgr->compactAllFolders( false /*scheduled, not immediate*/ ); 02370 // the_searchFolderMgr: no compaction 02371 } 02372 02373 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h 02374 mBackgroundTasksTimer->start( 60 * 1000, true ); // check again in 1 minute 02375 #else 02376 mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours 02377 #endif 02378 02379 } 02380 02381 void KMKernel::expireAllFoldersNow() // called by the GUI 02382 { 02383 the_folderMgr->expireAllFolders( true /*immediate*/ ); 02384 the_imapFolderMgr->expireAllFolders( true /*immediate*/ ); 02385 the_dimapFolderMgr->expireAllFolders( true /*immediate*/ ); 02386 } 02387 02388 void KMKernel::compactAllFolders() // called by the GUI 02389 { 02390 the_folderMgr->compactAllFolders( true /*immediate*/ ); 02391 //the_imapFolderMgr->compactAllFolders( true /*immediate*/ ); 02392 the_dimapFolderMgr->compactAllFolders( true /*immediate*/ ); 02393 } 02394 02395 KMFolder* KMKernel::findFolderById( const TQString& idString ) 02396 { 02397 KMFolder * folder = the_folderMgr->findIdString( idString ); 02398 if ( !folder ) 02399 folder = the_imapFolderMgr->findIdString( idString ); 02400 if ( !folder ) 02401 folder = the_dimapFolderMgr->findIdString( idString ); 02402 if ( !folder ) 02403 folder = the_searchFolderMgr->findIdString( idString ); 02404 return folder; 02405 } 02406 02407 ::KIMProxy* KMKernel::imProxy() 02408 { 02409 return KIMProxy::instance( kapp->dcopClient() ); 02410 } 02411 02412 void KMKernel::enableMailCheck() 02413 { 02414 mMailCheckAborted = false; 02415 } 02416 02417 bool KMKernel::mailCheckAborted() const 02418 { 02419 return mMailCheckAborted; 02420 } 02421 02422 void KMKernel::abortMailCheck() 02423 { 02424 mMailCheckAborted = true; 02425 } 02426 02427 bool KMKernel::canQueryClose() 02428 { 02429 if ( KMMainWidget::mainWidgetList() && 02430 KMMainWidget::mainWidgetList()->count() > 1 ) 02431 return true; 02432 KMMainWidget *widget = getKMMainWidget(); 02433 if ( !widget ) 02434 return true; 02435 KMSystemTray* systray = widget->systray(); 02436 if ( !systray || GlobalSettings::closeDespiteSystemTray() ) 02437 return true; 02438 if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) { 02439 systray->hideKMail(); 02440 return false; 02441 } else if ( ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) && ( systray->hasUnreadMail() )) { 02442 systray->show(); 02443 systray->hideKMail(); 02444 return false; 02445 } 02446 return true; 02447 } 02448 02449 void KMKernel::messageCountChanged() 02450 { 02451 mTimeOfLastMessageCountChange = ::time( 0 ); 02452 } 02453 02454 int KMKernel::timeOfLastMessageCountChange() const 02455 { 02456 return mTimeOfLastMessageCountChange; 02457 } 02458 02459 Wallet *KMKernel::wallet() { 02460 static bool walletOpenFailed = false; 02461 if ( mWallet && mWallet->isOpen() ) 02462 return mWallet; 02463 02464 if ( !Wallet::isEnabled() || walletOpenFailed ) 02465 return 0; 02466 02467 // find an appropriate parent window for the wallet dialog 02468 WId window = 0; 02469 if ( tqApp->activeWindow() ) 02470 window = tqApp->activeWindow()->winId(); 02471 else if ( getKMMainWidget() ) 02472 window = getKMMainWidget()->topLevelWidget()->winId(); 02473 02474 delete mWallet; 02475 mWallet = Wallet::openWallet( Wallet::NetworkWallet(), window ); 02476 02477 if ( !mWallet ) { 02478 walletOpenFailed = true; 02479 return 0; 02480 } 02481 02482 if ( !mWallet->hasFolder( "kmail" ) ) 02483 mWallet->createFolder( "kmail" ); 02484 mWallet->setFolder( "kmail" ); 02485 return mWallet; 02486 } 02487 02488 TQValueList< TQGuardedPtr<KMFolder> > KMKernel::allFolders() 02489 { 02490 TQStringList names; 02491 TQValueList<TQGuardedPtr<KMFolder> > folders; 02492 folderMgr()->createFolderList(&names, &folders); 02493 imapFolderMgr()->createFolderList(&names, &folders); 02494 dimapFolderMgr()->createFolderList(&names, &folders); 02495 searchFolderMgr()->createFolderList(&names, &folders); 02496 02497 return folders; 02498 } 02499 02500 KMFolder *KMKernel::currentFolder() { 02501 KMMainWidget *widget = getKMMainWidget(); 02502 KMFolder *folder = 0; 02503 if ( widget && widget->folderTree() ) { 02504 folder = widget->folderTree()->currentFolder(); 02505 } 02506 return folder; 02507 } 02508 02509 // can't be inline, since KMSender isn't known to implement 02510 // KMail::MessageSender outside this .cpp file 02511 KMail::MessageSender * KMKernel::msgSender() { return the_msgSender; } 02512 02513 #include "kmkernel.moc"