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