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