00001
00002
00003
00004
00005 #include "kmfoldermaildir.h"
00006
00007 #include <QDir>
00008 #include <QRegExp>
00009 #include <QByteArray>
00010 #include <QFileInfo>
00011
00012 #include <kpimutils/kfileio.h>
00013 #include "kmfoldermgr.h"
00014 #include "kmfolder.h"
00015 #include "undostack.h"
00016 #include "maildirjob.h"
00017 #include "kcursorsaver.h"
00018 #include "jobscheduler.h"
00019 using KMail::MaildirJob;
00020 #include "compactionjob.h"
00021 #include "kmmsgdict.h"
00022 #include "util.h"
00023
00024 #include <kio/directorysizejob.h>
00025
00026 #include <kdebug.h>
00027 #include <kde_file.h>
00028 #include <kfileitem.h>
00029 #include <kglobal.h>
00030 #include <klocale.h>
00031 #include <kmessagebox.h>
00032 #include <krandom.h>
00033
00034 #include <QDateTime>
00035 #include <QPointer>
00036
00037 #include <dirent.h>
00038 #include <errno.h>
00039 #include <stdlib.h>
00040 #include <sys/stat.h>
00041 #include <sys/types.h>
00042 #include <unistd.h>
00043 #include <assert.h>
00044 #include <limits.h>
00045 #include <fcntl.h>
00046
00047 #ifndef MAX_LINE
00048 #define MAX_LINE 4096
00049 #endif
00050 #ifndef INIT_MSGS
00051 #define INIT_MSGS 8
00052 #endif
00053
00054 using KPIMUtils::removeDirAndContentsRecursively;
00055
00056
00057
00058
00059
00060
00061 #ifdef Q_WS_WIN
00062 #define KMAIL_MAILDIR_FNAME_SEPARATOR "!"
00063 #else
00064 #define KMAIL_MAILDIR_FNAME_SEPARATOR ":"
00065 #endif
00066
00067 #ifdef KMAIL_SQLITE_INDEX
00068 #include <sqlite3.h>
00069 #endif
00070
00071
00072 KMFolderMaildir::KMFolderMaildir(KMFolder* folder, const char* name)
00073 : KMFolderIndex(folder, name), mCurrentlyCheckingFolderSize(false)
00074 {
00075
00076 }
00077
00078
00079
00080 KMFolderMaildir::~KMFolderMaildir()
00081 {
00082 if ( mOpenCount > 0 ) {
00083 close( "~foldermaildir", true );
00084 }
00085 if ( kmkernel->undoStack() ) {
00086 kmkernel->undoStack()->folderDestroyed( folder() );
00087 }
00088 }
00089
00090
00091 bool KMFolderMaildir::canAccess() const
00092 {
00093 assert(!folder()->name().isEmpty());
00094
00095 QString sBadFolderName;
00096 QStringList files;
00097 files << "" << "/new" << "/cur" << "/tmp";
00098 foreach( const QString& fname, files ) {
00099 QFileInfo finfo( location() + fname );
00100 if ( !finfo.isDir() || !finfo.isReadable() || !finfo.isWritable() ) {
00101 sBadFolderName = location() + fname;
00102 break;
00103 }
00104 }
00105
00106 if ( sBadFolderName.isEmpty() )
00107 return true;
00108
00109 KCursorSaver idle(KBusyPtr::idle());
00110 if ( !QFile::exists(sBadFolderName) )
00111 KMessageBox::sorry(0, i18n("Error opening %1; this folder is missing.",
00112 sBadFolderName));
00113 else
00114 KMessageBox::sorry(0, i18n("Error opening %1; either this is not a valid "
00115 "maildir folder, or you do not have sufficient access permissions.",
00116 sBadFolderName));
00117 return false;
00118 }
00119
00120
00121 int KMFolderMaildir::open( const char * )
00122 {
00123 mOpenCount++;
00124 kmkernel->jobScheduler()->notifyOpeningFolder( folder() );
00125
00126 if (mOpenCount > 1) return 0;
00127
00128 assert(!folder()->name().isEmpty());
00129
00130 if ( !canAccess() )
00131 return 1;
00132
00133 int rc = openInternal( NoOptions );
00134
00135 return rc;
00136 }
00137
00138
00139 int KMFolderMaildir::createMaildirFolders( const QString &folderPath )
00140 {
00141
00142 QFileInfo dirinfo;
00143 dirinfo.setFile( folderPath + "/new" );
00144 if ( dirinfo.exists() ) {
00145 return EEXIST;
00146 }
00147
00148 dirinfo.setFile( folderPath + "/cur" );
00149 if ( dirinfo.exists() ) {
00150 return EEXIST;
00151 }
00152
00153 dirinfo.setFile( folderPath + "/tmp" );
00154 if ( dirinfo.exists() ) {
00155 return EEXIST;
00156 }
00157
00158
00159 if ( KDE_mkdir( QFile::encodeName( folderPath ), S_IRWXU ) > 0 ) {
00160 kDebug(5006) << "Could not create folder" << folderPath;
00161 return errno;
00162 }
00163 if ( KDE_mkdir( QFile::encodeName( folderPath + "/new" ), S_IRWXU ) > 0 ) {
00164 kDebug(5006) << "Could not create folder" << folderPath << "/new";
00165 return errno;
00166 }
00167 if ( KDE_mkdir( QFile::encodeName( folderPath + "/cur" ), S_IRWXU ) > 0 ) {
00168 kDebug(5006) << "Could not create folder" << folderPath << "/cur";
00169 return errno;
00170 }
00171 if ( KDE_mkdir( QFile::encodeName( folderPath + "/tmp" ), S_IRWXU ) > 0 ) {
00172 kDebug(5006) << "Could not create folder" << folderPath << "/tmp";
00173 return errno;
00174 }
00175
00176 return 0;
00177 }
00178
00179
00180 int KMFolderMaildir::create()
00181 {
00182 assert(!folder()->name().isEmpty());
00183 assert(mOpenCount == 0);
00184
00185 int rc = createMaildirFolders( location() );
00186 if ( rc != 0 )
00187 return rc;
00188
00189
00190 return createInternal();
00191 }
00192
00193
00194
00195 void KMFolderMaildir::reallyDoClose()
00196 {
00197 if (mAutoCreateIndex)
00198 {
00199 updateIndex( true );
00200 writeConfig();
00201 }
00202
00203 mMsgList.clear(true);
00204
00205 #ifdef KMAIL_SQLITE_INDEX
00206 if ( mIndexDb ) {
00207 sqlite3_close( mIndexDb );
00208 mIndexDb = 0;
00209 }
00210 #else
00211 if (mIndexStream) {
00212 fclose(mIndexStream);
00213 kDebug( StorageDebug ) << "fclose(mIndexStream = " << mIndexStream << ")";
00214 updateIndexStreamPtr(true);
00215 }
00216 mIndexStream = 0;
00217 #endif
00218
00219 mOpenCount = 0;
00220 mUnreadMsgs = -1;
00221
00222 mMsgList.reset(INIT_MSGS);
00223 }
00224
00225
00226 void KMFolderMaildir::sync()
00227 {
00228 #ifdef KMAIL_SQLITE_INDEX
00229 #else
00230 if (mOpenCount > 0)
00231 if (!mIndexStream || fsync(fileno(mIndexStream))) {
00232 kmkernel->emergencyExit( i18n("Could not sync maildir folder.") );
00233 }
00234 #endif
00235 }
00236
00237
00238 int KMFolderMaildir::expungeContents()
00239 {
00240
00241 QDir d( location() + "/new" );
00242 QStringList files( d.entryList( QDir::Files | QDir::NoDotAndDotDot ) );
00243 foreach ( const QString& file, files )
00244 QFile::remove( d.filePath(file) );
00245
00246 d.setPath(location() + "/cur");
00247 files = d.entryList( QDir::Files | QDir::NoDotAndDotDot );
00248 foreach ( const QString& file, files )
00249 QFile::remove( d.filePath( file ) );
00250
00251 return 0;
00252 }
00253
00254 int KMFolderMaildir::compact( unsigned int startIndex, int nbMessages, const QStringList& entryList, bool& done )
00255 {
00256 QString subdirNew(location() + "/new/");
00257 QString subdirCur(location() + "/cur/");
00258
00259 unsigned int stopIndex = nbMessages == -1 ? mMsgList.count() :
00260 qMin( mMsgList.count(), startIndex + nbMessages );
00261
00262 for(unsigned int idx = startIndex; idx < stopIndex; ++idx) {
00263 KMMsgInfo* mi = (KMMsgInfo*)mMsgList.at(idx);
00264 if (!mi)
00265 continue;
00266
00267 QString filename(mi->fileName());
00268 if (filename.isEmpty())
00269 continue;
00270
00271
00272 if ( entryList.contains( filename ) )
00273 moveInternal(subdirNew + filename, subdirCur + filename, mi);
00274
00275
00276
00277 filename = constructValidFileName( filename, mi->messageStatus() );
00278
00279
00280 if (filename != mi->fileName())
00281 {
00282 moveInternal(subdirCur + mi->fileName(), subdirCur + filename, mi);
00283 mi->setFileName(filename);
00284 setDirty( true );
00285 }
00286
00287 #if 0
00288
00289 if (mi->isNew())
00290 {
00291 mi->setStatus(KMMsgStatusUnread);
00292 setDirty( true );
00293 }
00294 #endif
00295 }
00296 done = ( stopIndex == mMsgList.count() );
00297 return 0;
00298 }
00299
00300
00301 int KMFolderMaildir::compact( bool silent )
00302 {
00303 KMail::MaildirCompactionJob* job = new KMail::MaildirCompactionJob( folder(), true );
00304 int rc = job->executeNow( silent );
00305
00306 return rc;
00307 }
00308
00309
00310 FolderJob*
00311 KMFolderMaildir::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
00312 KMFolder *folder, const QString&, const AttachmentStrategy* ) const
00313 {
00314 MaildirJob *job = new MaildirJob( msg, jt, folder );
00315 job->setParentFolder( this );
00316 return job;
00317 }
00318
00319
00320 FolderJob*
00321 KMFolderMaildir::doCreateJob( QList<KMMessage*>& msgList, const QString& sets,
00322 FolderJob::JobType jt, KMFolder *folder ) const
00323 {
00324 MaildirJob *job = new MaildirJob( msgList, sets, jt, folder );
00325 job->setParentFolder( this );
00326 return job;
00327 }
00328
00329
00330 int KMFolderMaildir::addMsg(KMMessage* aMsg, int* index_return)
00331 {
00332 if (!canAddMsgNow(aMsg, index_return)) return 0;
00333 return addMsgInternal( aMsg, index_return );
00334 }
00335
00336
00337 int KMFolderMaildir::addMsgInternal( KMMessage* aMsg, int* index_return,
00338 bool stripUid )
00339 {
00340
00341
00342
00343
00344
00345
00346
00347
00348 int idx(-1);
00349
00350
00351 KMFolder* msgParent = aMsg->parent();
00352 if (msgParent)
00353 {
00354 if (msgParent==folder() && !kmkernel->folderIsDraftOrOutbox(folder()))
00355 return 0;
00356
00357 idx = msgParent->find(aMsg);
00358 msgParent->getMsg( idx );
00359 }
00360
00361 aMsg->setStatusFields();
00362 if (aMsg->headerField("Content-Type").isEmpty())
00363 aMsg->removeHeaderField("Content-Type");
00364
00365
00366 const QString uidHeader = aMsg->headerField( "X-UID" );
00367 if ( !uidHeader.isEmpty() && stripUid )
00368 aMsg->removeHeaderField( "X-UID" );
00369
00370 const QByteArray msgText = aMsg->asString();
00371
00372
00373
00374 if ( !uidHeader.isEmpty() && stripUid )
00375 aMsg->setHeaderField( "X-UID", uidHeader );
00376
00377 if ( msgText.isEmpty() ) {
00378 kDebug(5006) <<"Message added to folder `" << objectName() <<"' contains no data. Ignoring it.";
00379 return 0;
00380 }
00381
00382
00383 QString filename = constructValidFileName( aMsg->fileName(), aMsg->messageStatus() );
00384
00385 QString tmp_file(location() + "/tmp/");
00386 tmp_file += filename;
00387
00388 if ( ! KPIMUtils::kByteArrayToFile( msgText, tmp_file, false, false, false ) )
00389 kmkernel->emergencyExit( i18n("Message could not be added to the folder, possibly disk space is low.") );
00390
00391 QFile file(tmp_file);
00392
00393 KMFolderOpener openThis(folder(), "maildir");
00394 if (openThis.openResult())
00395 {
00396 kDebug(5006) << openThis.openResult() << "of folder:" << label();
00397 return openThis.openResult();
00398 }
00399
00400
00401 QString new_loc(location() + "/cur/");
00402 new_loc += filename;
00403 if (moveInternal(tmp_file, new_loc, filename, aMsg->messageStatus()).isEmpty())
00404 {
00405 file.remove();
00406 return -1;
00407 }
00408
00409 if (msgParent && idx >= 0)
00410 msgParent->take(idx);
00411
00412
00413 if ( stripUid ) aMsg->setUID( 0 );
00414
00415 if (filename != aMsg->fileName())
00416 aMsg->setFileName(filename);
00417
00418 if ( aMsg->status().isUnread() || aMsg->status().isNew() ||
00419 folder() == kmkernel->outboxFolder())
00420 {
00421 if (mUnreadMsgs == -1)
00422 mUnreadMsgs = 1;
00423 else
00424 ++mUnreadMsgs;
00425 if ( !mQuiet ) {
00426 kDebug( 5006 ) << "FolderStorage::msgStatusChanged";
00427 emit numUnreadMsgsChanged( folder() );
00428 }else{
00429 if ( !mEmitChangedTimer->isActive() ) {
00430
00431 mEmitChangedTimer->start( 3000 );
00432 }
00433 mChanged = true;
00434 }
00435 }
00436 ++mTotalMsgs;
00437 mSize = -1;
00438
00439 if ( aMsg->attachmentState() == KMMsgAttachmentUnknown &&
00440 aMsg->readyToShow() )
00441 aMsg->updateAttachmentState();
00442
00443
00444 aMsg->setParent(folder());
00445 aMsg->setMsgSize( msgText.length() );
00446 idx = mMsgList.append( &aMsg->toMsgBase(), mExportsSernums );
00447 const unsigned long msgSerNum = aMsg->getMsgSerNum();
00448 kDebug( Test1Area ) << "getMsgSerNum:" << msgSerNum;
00449 if ( msgSerNum <= 0 )
00450 aMsg->setMsgSerNum();
00451 else
00452 replaceMsgSerNum( msgSerNum, &aMsg->toMsgBase(), idx );
00453
00454
00455 if (mAutoCreateIndex)
00456 {
00457 #ifdef KMAIL_SQLITE_INDEX
00458
00459
00460 aMsg->setDbId( 0 );
00461 aMsg->setDirty( true );
00462 #else
00463 assert(mIndexStream != 0);
00464 clearerr(mIndexStream);
00465 KDE_fseek(mIndexStream, 0, SEEK_END);
00466 off_t revert = KDE_ftell(mIndexStream);
00467 #endif
00468
00469 KMMsgBase * mb = &aMsg->toMsgBase();
00470 int error = writeMessages( mb, true );
00471 if ( error )
00472 kDebug(5006) << "Error: writing the index for this folder failed";
00473
00474 if ( mExportsSernums )
00475 error |= appendToFolderIdsFile( idx );
00476
00477 if ( error ) {
00478 kDebug(5006) << "Error: Could not add message to folder (No space left on device?)";
00479 #ifdef KMAIL_SQLITE_INDEX
00480 #else
00481 if ( KDE_ftell( mIndexStream ) > revert ) {
00482 kDebug(5006) << "Undoing changes";
00483 truncate( QFile::encodeName( indexLocation() ), revert );
00484 }
00485 #endif
00486 kmkernel->emergencyExit(i18n("KMFolderMaildir::addMsg: abnormally terminating to prevent data loss."));
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 return error;
00499 }
00500 }
00501
00502 if (index_return)
00503 *index_return = idx;
00504
00505 emitMsgAddedSignals(idx);
00506 needsCompact = true;
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 return 0;
00517 }
00518
00519 KMMessage* KMFolderMaildir::readMsg(int idx)
00520 {
00521 KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
00522 KMMessage *msg = new KMMessage(*mi);
00523 mMsgList.set(idx,&msg->toMsgBase());
00524 msg->setComplete( true );
00525 msg->fromDwString(getDwString(idx));
00526 return msg;
00527 }
00528
00529 DwString KMFolderMaildir::getDwString(int idx)
00530 {
00531 KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
00532 QString abs_file(location() + "/cur/");
00533 abs_file += mi->fileName();
00534 QFileInfo fi( abs_file );
00535
00536 if (fi.exists() && fi.isFile() && fi.isWritable() && fi.size() > 0)
00537 {
00538 FILE* stream = KDE_fopen(QFile::encodeName(abs_file), "r+");
00539 kDebug( StorageDebug ) << "KDE_fopen(abs_file=" << abs_file << ", \"r+\") == stream == " << stream;
00540 if (stream) {
00541 size_t msgSize = fi.size();
00542 char* msgText = new char[ msgSize + 1 ];
00543 fread(msgText, msgSize, 1, stream);
00544 fclose( stream );
00545 kDebug( StorageDebug ) << "fclose(mIndexStream = " << stream << ")";
00546 msgText[msgSize] = '\0';
00547 size_t newMsgSize = KMail::Util::crlf2lf( msgText, msgSize );
00548 DwString str;
00549
00550 str.TakeBuffer( msgText, msgSize + 1, 0, newMsgSize );
00551 return str;
00552 }
00553 }
00554 kDebug(5006) <<"Could not open file r+" << abs_file;
00555 return DwString();
00556 }
00557
00558
00559 void KMFolderMaildir::readFileHeaderIntern( const QString& dir,
00560 const QString& file,
00561 MessageStatus& status )
00562 {
00563
00564 char path_buffer[PATH_MAX];
00565 if ( !::getcwd( path_buffer, PATH_MAX - 1 ) ) {
00566 return;
00567 }
00568
00569 ::chdir( QFile::encodeName( dir ) );
00570
00571
00572
00573 if ( status.isRead() ) {
00574 if ( !file.contains(KMAIL_MAILDIR_FNAME_SEPARATOR "2,") ) {
00575 status.setUnread();
00576 } else if ( file.right(5) == KMAIL_MAILDIR_FNAME_SEPARATOR "2,RS" ) {
00577 status.setReplied();
00578 }
00579 }
00580
00581
00582 QFile f( file );
00583 if ( f.open( QIODevice::ReadOnly ) == false ) {
00584 kWarning(5006) <<"The file '" << QFile::encodeName(dir) <<"/" << file
00585 << "' could not be opened for reading the message."
00586 << "Please check ownership and permissions.";
00587 return;
00588 }
00589
00590 char line[MAX_LINE];
00591 bool atEof = false;
00592 bool inHeader = true;
00593 QByteArray *lastStr = 0;
00594
00595 QByteArray dateStr, fromStr, toStr, subjStr;
00596 QByteArray xmarkStr, replyToIdStr, msgIdStr, referencesStr;
00597 QByteArray statusStr, replyToAuxIdStr, uidStr;
00598 QByteArray contentTypeStr, charset;
00599
00600
00601 while (!atEof) {
00602
00603 if ( f.atEnd() || ( -1 == f.readLine(line, MAX_LINE) ) ) {
00604 atEof = true;
00605 }
00606
00607
00608
00609 if (atEof || !inHeader)
00610 {
00611 msgIdStr = msgIdStr.trimmed();
00612 if( !msgIdStr.isEmpty() ) {
00613 int rightAngle;
00614 rightAngle = msgIdStr.indexOf( '>' );
00615 if( rightAngle != -1 )
00616 msgIdStr.truncate( rightAngle + 1 );
00617 }
00618
00619 replyToIdStr = replyToIdStr.trimmed();
00620 if( !replyToIdStr.isEmpty() ) {
00621 int rightAngle;
00622 rightAngle = replyToIdStr.indexOf( '>' );
00623 if( rightAngle != -1 )
00624 replyToIdStr.truncate( rightAngle + 1 );
00625 }
00626
00627 referencesStr = referencesStr.trimmed();
00628 if( !referencesStr.isEmpty() ) {
00629 int leftAngle, rightAngle;
00630 leftAngle = referencesStr.lastIndexOf( '<' );
00631 if( ( leftAngle != -1 )
00632 && ( replyToIdStr.isEmpty() || ( replyToIdStr[0] != '<' ) ) ) {
00633
00634 replyToIdStr = referencesStr.mid( leftAngle );
00635 }
00636
00637
00638 leftAngle = referencesStr.lastIndexOf( '<', leftAngle - 1 );
00639 if( leftAngle != -1 )
00640 referencesStr = referencesStr.mid( leftAngle );
00641 rightAngle = referencesStr.lastIndexOf( '>' );
00642 if( rightAngle != -1 )
00643 referencesStr.truncate( rightAngle + 1 );
00644
00645
00646
00647
00648
00649 replyToAuxIdStr = referencesStr;
00650 rightAngle = referencesStr.indexOf( '>' );
00651 if( rightAngle != -1 )
00652 replyToAuxIdStr.truncate( rightAngle + 1 );
00653 }
00654
00655 statusStr = statusStr.trimmed();
00656 if (!statusStr.isEmpty())
00657 {
00658
00659 if (statusStr[0] == 'S')
00660 status.setSent();
00661 else if (statusStr[0] == 'F')
00662 status.setForwarded();
00663 else if (statusStr[0] == 'D')
00664 status.setDeleted();
00665 else if (statusStr[0] == 'Q')
00666 status.setQueued();
00667 else if (statusStr[0] == 'G')
00668 status.setImportant();
00669 }
00670
00671 contentTypeStr = contentTypeStr.trimmed();
00672 charset = "";
00673 if ( !contentTypeStr.isEmpty() ) {
00674 int cidx = contentTypeStr.indexOf( "charset=" );
00675 if ( cidx != -1 ) {
00676 charset = contentTypeStr.mid( cidx + 8 );
00677 if ( charset[0] == '"' ) {
00678 charset = charset.mid( 1 );
00679 }
00680 cidx = 0;
00681 while ( cidx < charset.length() ) {
00682 if ( charset[cidx] == '"' ||
00683 ( !isalnum(charset[cidx] ) &&
00684 charset[cidx] != '-' && charset[cidx] != '_' ) ) {
00685 break;
00686 }
00687 ++cidx;
00688 }
00689 charset.truncate( cidx );
00690 }
00691 }
00692
00693 KMMsgInfo *mi = new KMMsgInfo(folder());
00694 mi->init( subjStr.trimmed(),
00695 fromStr.trimmed(),
00696 toStr.trimmed(),
00697 0, status,
00698 xmarkStr.trimmed(),
00699 replyToIdStr, replyToAuxIdStr, msgIdStr,
00700 file.toLocal8Bit(),
00701 KMMsgEncryptionStateUnknown, KMMsgSignatureStateUnknown,
00702 KMMsgMDNStateUnknown, charset, f.size() );
00703
00704 dateStr = dateStr.trimmed();
00705 if (!dateStr.isEmpty())
00706 mi->setDate(dateStr.constData());
00707 if ( !uidStr.isEmpty() )
00708 mi->setUID( uidStr.toULong() );
00709 mi->setDirty(false);
00710 mMsgList.append( mi, mExportsSernums );
00711
00712
00713 if ( status.isNew() )
00714 {
00715 QString newDir(location() + "/new/");
00716 QString curDir(location() + "/cur/");
00717 moveInternal(newDir + file, curDir + file, mi);
00718 }
00719
00720 break;
00721 }
00722
00723
00724 if (inHeader && line[0] == '\t' || line[0] == ' ')
00725 {
00726 int i = 0;
00727 while (line[i] == '\t' || line[i] == ' ')
00728 i++;
00729 if (line[i] < ' ' && line[i] > 0)
00730 inHeader = false;
00731 else
00732 if (lastStr)
00733 *lastStr += line + i;
00734 }
00735 else
00736 lastStr = 0;
00737
00738 if (inHeader && (line[0] == '\n' || line[0] == '\r'))
00739 inHeader = false;
00740 if (!inHeader)
00741 continue;
00742
00743 if ( strncasecmp(line, "Date:", 5) == 0) {
00744 dateStr = QByteArray( line + 5 );
00745 lastStr = &dateStr;
00746 } else if ( strncasecmp( line, "From:", 5 ) == 0 ) {
00747 fromStr = QByteArray( line + 5 );
00748 lastStr = &fromStr;
00749 } else if ( strncasecmp( line, "To:", 3 ) == 0 ) {
00750 toStr = QByteArray( line + 3 );
00751 lastStr = &toStr;
00752 } else if ( strncasecmp( line, "Subject:", 8 ) == 0 ) {
00753 subjStr = QByteArray( line + 8 );
00754 lastStr = &subjStr;
00755 } else if ( strncasecmp( line, "References:", 11 ) == 0 ) {
00756 referencesStr = QByteArray( line + 11 );
00757 lastStr = &referencesStr;
00758 } else if ( strncasecmp( line, "Message-Id:", 11 ) == 0 ) {
00759 msgIdStr = QByteArray( line + 11 );
00760 lastStr = &msgIdStr;
00761 } else if ( strncasecmp( line, "X-KMail-Mark:", 13 ) == 0 ) {
00762 xmarkStr = QByteArray( line + 13 );
00763 } else if ( strncasecmp( line, "X-Status:", 9 ) == 0 ) {
00764 statusStr = QByteArray( line + 9 );
00765 } else if ( strncasecmp( line, "In-Reply-To:", 12 ) == 0 ) {
00766 replyToIdStr = QByteArray( line + 12 );
00767 lastStr = &replyToIdStr;
00768 } else if ( strncasecmp( line, "X-UID:", 6 ) == 0 ) {
00769 uidStr = QByteArray( line + 6 );
00770 lastStr = &uidStr;
00771 } else if ( strncasecmp( line, "Content-Type:", 13 ) == 0) {
00772 contentTypeStr = QByteArray( line + 13 );
00773 lastStr = &contentTypeStr;
00774 }
00775
00776 }
00777
00778 if ( status.isNew() || status.isUnread() ||
00779 (folder() == kmkernel->outboxFolder()))
00780 {
00781 mUnreadMsgs++;
00782 if (mUnreadMsgs == 0) ++mUnreadMsgs;
00783 }
00784
00785 ::chdir(path_buffer);
00786 }
00787
00788 int KMFolderMaildir::createIndexFromContents()
00789 {
00790 kDebug() << "Creating index for" << location();
00791
00792 mUnreadMsgs = 0;
00793
00794 mMsgList.clear(true);
00795 mMsgList.reset(INIT_MSGS);
00796
00797 mChanged = false;
00798
00799
00800
00801 QFileInfo dirinfo;
00802
00803 dirinfo.setFile(location() + "/new");
00804 if (!dirinfo.exists() || !dirinfo.isDir())
00805 {
00806 kDebug(5006) << "Directory" << location() <<"/new doesn't exist or is a file";
00807 return 1;
00808 }
00809 QDir newDir(location() + "/new");
00810 newDir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
00811
00812 dirinfo.setFile(location() + "/cur");
00813 if (!dirinfo.exists() || !dirinfo.isDir())
00814 {
00815 kDebug(5006) << "Directory" << location() <<"/cur doesn't exist or is a file";
00816 return 1;
00817 }
00818 QDir curDir(location() + "/cur");
00819 curDir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
00820
00821
00822 foreach( const QFileInfo& fi, curDir.entryInfoList() )
00823 {
00824 MessageStatus st = MessageStatus::statusRead();
00825 readFileHeaderIntern( curDir.path(), fi.fileName(), st );
00826 }
00827
00828
00829 foreach( const QFileInfo& fi, newDir.entryInfoList() )
00830 {
00831 MessageStatus st = MessageStatus::statusNew();
00832 readFileHeaderIntern( newDir.path(), fi.fileName(), st );
00833 }
00834
00835 if ( autoCreateIndex() ) {
00836 emit statusMsg(i18n("Writing index file"));
00837 writeIndex();
00838 }
00839 else {
00840 #ifdef KMAIL_SQLITE_INDEX
00841 #else
00842 mHeaderOffset = 0;
00843 #endif
00844 }
00845
00846 correctUnreadMsgsCount();
00847
00848 if (kmkernel->outboxFolder() == folder() && count() > 0)
00849 KMessageBox::information(0, i18n("Your outbox contains messages which were "
00850 "most-likely not created by KMail;\nplease remove them from there if you "
00851 "do not want KMail to send them."));
00852
00853 needsCompact = true;
00854
00855 invalidateFolder();
00856 return 0;
00857 }
00858
00859 KMFolderIndex::IndexStatus KMFolderMaildir::indexStatus()
00860 {
00861 QFileInfo new_info(location() + "/new");
00862 QFileInfo cur_info(location() + "/cur");
00863 QFileInfo index_info(indexLocation());
00864
00865 if (!index_info.exists())
00866 return KMFolderIndex::IndexMissing;
00867
00868
00869
00870
00871 KMFolderIndex::IndexStatus status =
00872 ( ( new_info.lastModified() > index_info.lastModified().addSecs( 5 ) ) ||
00873 ( cur_info.lastModified() > index_info.lastModified().addSecs( 5 ) ) )
00874 ? KMFolderIndex::IndexTooOld
00875 : KMFolderIndex::IndexOk;
00876 if ( status == KMFolderIndex::IndexTooOld ) {
00877 kWarning() << "Index" << indexLocation() << "out of date!";
00878 kWarning() << " new:" << new_info.lastModified();
00879 kWarning() << " cur:" << cur_info.lastModified();
00880 kWarning() << " index:" << index_info.lastModified();
00881 }
00882 return status;
00883 }
00884
00885
00886 void KMFolderMaildir::removeMsg(int idx, bool)
00887 {
00888 KMMsgBase* msg = mMsgList[idx];
00889 if (!msg || msg->fileName().isNull()) return;
00890
00891 removeFile(msg->fileName());
00892
00893 KMFolderIndex::removeMsg(idx);
00894 }
00895
00896
00897 KMMessage* KMFolderMaildir::take(int idx)
00898 {
00899
00900 KMMessage *msg = KMFolderIndex::take(idx);
00901
00902 if (!msg || msg->fileName().isNull()) {
00903 return 0;
00904 }
00905
00906 if ( removeFile(msg->fileName()) ) {
00907 return msg;
00908 } else {
00909 return 0;
00910 }
00911 }
00912
00913
00914
00915 bool KMFolderMaildir::removeFile( const QString & folderPath,
00916 const QString & filename )
00917 {
00918
00919
00920
00921
00922 QByteArray abs_file( QFile::encodeName( folderPath + "/cur/" + filename ) );
00923 if ( ::unlink( abs_file ) == 0 )
00924 return true;
00925
00926 if ( errno == ENOENT ) {
00927 abs_file = QFile::encodeName( folderPath + "/new/" + filename );
00928 if ( ::unlink( abs_file ) == 0 )
00929 return true;
00930 }
00931
00932 kDebug(5006) <<"Can't delete" << abs_file << perror;
00933 return false;
00934 }
00935
00936