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
00523 msg->fromDwString(getDwString(idx));
00524 mMsgList.set(idx,&msg->toMsgBase());
00525
return msg;
00526 }
00527
00528 DwString KMFolderMaildir::getDwString(
int idx)
00529 {
00530 KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
00531
QString abs_file(location() +
"/cur/");
00532 abs_file += mi->fileName();
00533
QFileInfo fi( abs_file );
00534
00535
if (fi.exists() && fi.isFile() && fi.isWritable() && fi.size() > 0)
00536 {
00537 FILE* stream = fopen(QFile::encodeName(abs_file),
"r+");
00538
if (stream) {
00539 size_t msgSize = fi.size();
00540
char* msgText =
new char[ msgSize + 1 ];
00541 fread(msgText, msgSize, 1, stream);
00542 fclose( stream );
00543 msgText[msgSize] =
'\0';
00544 size_t newMsgSize = crlf2lf( msgText, msgSize );
00545 DwString str;
00546
00547 str.TakeBuffer( msgText, msgSize + 1, 0, newMsgSize );
00548
return str;
00549 }
00550 }
00551 kdDebug(5006) <<
"Could not open file r+ " << abs_file << endl;
00552
return DwString();
00553 }
00554
00555
00556
QCString& KMFolderMaildir::getMsgString(
int idx,
QCString& mDest)
00557 {
00558 KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
00559
00560 assert(mi!=0);
00561
00562
QString abs_file(location() +
"/cur/");
00563 abs_file += mi->fileName();
00564
00565
if (QFile::exists(abs_file) ==
false)
00566 {
00567 kdDebug(5006) <<
"The " << abs_file <<
" file doesn't exist!" << endl;
00568
return mDest;
00569 }
00570
00571
QFileInfo fi( abs_file );
00572 mDest.resize(fi.size()+2);
00573 mDest = KPIM::kFileToString(abs_file,
false,
false);
00574 size_t newMsgSize = crlf2lf( mDest.data(), fi.size() );
00575 mDest[newMsgSize] =
'\0';
00576
return mDest;
00577 }
00578
00579
void KMFolderMaildir::readFileHeaderIntern(
const QString& dir,
const QString& file, KMMsgStatus status)
00580 {
00581
00582
char path_buffer[PATH_MAX];
00583 ::getcwd(path_buffer, PATH_MAX - 1);
00584 ::chdir(QFile::encodeName(dir));
00585
00586
00587
00588
if (status == KMMsgStatusRead)
00589 {
00590
if (file.find(
":2,") == -1)
00591 status = KMMsgStatusUnread;
00592
else if (file.right(5) ==
":2,RS")
00593 status |= KMMsgStatusReplied;
00594 }
00595
00596
00597
QFile f(file);
00598
if ( f.open( IO_ReadOnly ) ==
false ) {
00599 kdWarning(5006) <<
"The file '" << QFile::encodeName(dir) <<
"/" << file
00600 <<
"' could not be opened for reading the message. "
00601
"Please check ownership and permissions."
00602 << endl;
00603
return;
00604 }
00605
00606
char line[MAX_LINE];
00607
bool atEof =
false;
00608
bool inHeader =
true;
00609
QCString *lastStr = 0;
00610
00611
QCString dateStr, fromStr, toStr, subjStr;
00612
QCString xmarkStr, replyToIdStr, msgIdStr, referencesStr;
00613
QCString statusStr, replyToAuxIdStr, uidStr;
00614
00615
00616
while (!atEof)
00617 {
00618
00619
if ( f.atEnd() || ( -1 == f.readLine(line, MAX_LINE) ) )
00620 atEof =
true;
00621
00622
00623
00624
if (atEof || !inHeader)
00625 {
00626 msgIdStr = msgIdStr.stripWhiteSpace();
00627
if( !msgIdStr.isEmpty() ) {
00628
int rightAngle;
00629 rightAngle = msgIdStr.find(
'>' );
00630
if( rightAngle != -1 )
00631 msgIdStr.truncate( rightAngle + 1 );
00632 }
00633
00634 replyToIdStr = replyToIdStr.stripWhiteSpace();
00635
if( !replyToIdStr.isEmpty() ) {
00636
int rightAngle;
00637 rightAngle = replyToIdStr.find(
'>' );
00638
if( rightAngle != -1 )
00639 replyToIdStr.truncate( rightAngle + 1 );
00640 }
00641
00642 referencesStr = referencesStr.stripWhiteSpace();
00643
if( !referencesStr.isEmpty() ) {
00644
int leftAngle, rightAngle;
00645 leftAngle = referencesStr.findRev(
'<' );
00646
if( ( leftAngle != -1 )
00647 && ( replyToIdStr.isEmpty() || ( replyToIdStr[0] !=
'<' ) ) ) {
00648
00649 replyToIdStr = referencesStr.mid( leftAngle );
00650 }
00651
00652
00653 leftAngle = referencesStr.findRev(
'<', leftAngle - 1 );
00654
if( leftAngle != -1 )
00655 referencesStr = referencesStr.mid( leftAngle );
00656 rightAngle = referencesStr.findRev(
'>' );
00657
if( rightAngle != -1 )
00658 referencesStr.truncate( rightAngle + 1 );
00659
00660
00661
00662
00663
00664 replyToAuxIdStr = referencesStr;
00665 rightAngle = referencesStr.find(
'>' );
00666
if( rightAngle != -1 )
00667 replyToAuxIdStr.truncate( rightAngle + 1 );
00668 }
00669
00670 statusStr = statusStr.stripWhiteSpace();
00671
if (!statusStr.isEmpty())
00672 {
00673
00674
if (statusStr[0] ==
'S')
00675 status |= KMMsgStatusSent;
00676
else if (statusStr[0] ==
'F')
00677 status |= KMMsgStatusForwarded;
00678
else if (statusStr[0] ==
'D')
00679 status |= KMMsgStatusDeleted;
00680
else if (statusStr[0] ==
'Q')
00681 status |= KMMsgStatusQueued;
00682
else if (statusStr[0] ==
'G')
00683 status |= KMMsgStatusFlag;
00684 }
00685
00686 KMMsgInfo *mi =
new KMMsgInfo(folder());
00687 mi->init( subjStr.stripWhiteSpace(),
00688 fromStr.stripWhiteSpace(),
00689 toStr.stripWhiteSpace(),
00690 0, status,
00691 xmarkStr.stripWhiteSpace(),
00692 replyToIdStr, replyToAuxIdStr, msgIdStr,
00693 file.local8Bit(),
00694 KMMsgEncryptionStateUnknown, KMMsgSignatureStateUnknown,
00695 KMMsgMDNStateUnknown, f.size() );
00696
00697 dateStr = dateStr.stripWhiteSpace();
00698
if (!dateStr.isEmpty())
00699 mi->setDate(dateStr);
00700
if ( !uidStr.isEmpty() )
00701 mi->setUID( uidStr.toULong() );
00702 mi->setDirty(
false);
00703 mMsgList.append(mi);
00704
00705
00706
if (status & KMMsgStatusNew)
00707 {
00708
QString newDir(location() +
"/new/");
00709
QString curDir(location() +
"/cur/");
00710 moveInternal(newDir + file, curDir + file, mi);
00711 }
00712
00713
break;
00714 }
00715
00716
00717
if (inHeader && line[0] ==
'\t' || line[0] ==
' ')
00718 {
00719
int i = 0;
00720
while (line[i] ==
'\t' || line[i] ==
' ')
00721 i++;
00722
if (line[i] <
' ' && line[i] > 0)
00723 inHeader =
false;
00724
else
00725
if (lastStr)
00726 *lastStr += line + i;
00727 }
00728
else
00729 lastStr = 0;
00730
00731
if (inHeader && (line[0] ==
'\n' || line[0] ==
'\r'))
00732 inHeader =
false;
00733
if (!inHeader)
00734
continue;
00735
00736
if (strncasecmp(line,
"Date:", 5) == 0)
00737 {
00738 dateStr =
QCString(line+5);
00739 lastStr = &dateStr;
00740 }
00741
else if (strncasecmp(line,
"From:", 5) == 0)
00742 {
00743 fromStr =
QCString(line+5);
00744 lastStr = &fromStr;
00745 }
00746
else if (strncasecmp(line,
"To:", 3) == 0)
00747 {
00748 toStr =
QCString(line+3);
00749 lastStr = &toStr;
00750 }
00751
else if (strncasecmp(line,
"Subject:", 8) == 0)
00752 {
00753 subjStr =
QCString(line+8);
00754 lastStr = &subjStr;
00755 }
00756
else if (strncasecmp(line,
"References:", 11) == 0)
00757 {
00758 referencesStr =
QCString(line+11);
00759 lastStr = &referencesStr;
00760 }
00761
else if (strncasecmp(line,
"Message-Id:", 11) == 0)
00762 {
00763 msgIdStr =
QCString(line+11);
00764 lastStr = &msgIdStr;
00765 }
00766
else if (strncasecmp(line,
"X-KMail-Mark:", 13) == 0)
00767 {
00768 xmarkStr =
QCString(line+13);
00769 }
00770
else if (strncasecmp(line,
"X-Status:", 9) == 0)
00771 {
00772 statusStr =
QCString(line+9);
00773 }
00774
else if (strncasecmp(line,
"In-Reply-To:", 12) == 0)
00775 {
00776 replyToIdStr =
QCString(line+12);
00777 lastStr = &replyToIdStr;
00778 }
00779
else if (strncasecmp(line,
"X-UID:", 6) == 0)
00780 {
00781 uidStr =
QCString(line+6);
00782 lastStr = &uidStr;
00783 }
00784
00785 }
00786
00787
if (status & KMMsgStatusNew || status & KMMsgStatusUnread ||
00788 (folder() == kmkernel->outboxFolder()))
00789 {
00790 mUnreadMsgs++;
00791
if (mUnreadMsgs == 0) ++mUnreadMsgs;
00792 }
00793
00794 ::chdir(path_buffer);
00795 }
00796
00797
int KMFolderMaildir::createIndexFromContents()
00798 {
00799 mUnreadMsgs = 0;
00800
00801 mMsgList.clear(
true);
00802 mMsgList.reset(INIT_MSGS);
00803
00804 mChanged =
false;
00805
00806
00807
00808
QFileInfo dirinfo;
00809
00810 dirinfo.setFile(location() +
"/new");
00811
if (!dirinfo.exists() || !dirinfo.isDir())
00812 {
00813 kdDebug(5006) <<
"Directory " << location() <<
"/new doesn't exist or is a file"<< endl;
00814
return 1;
00815 }
00816
QDir newDir(location() +
"/new");
00817 newDir.setFilter(QDir::Files);
00818
00819 dirinfo.setFile(location() +
"/cur");
00820
if (!dirinfo.exists() || !dirinfo.isDir())
00821 {
00822 kdDebug(5006) <<
"Directory " << location() <<
"/cur doesn't exist or is a file"<< endl;
00823
return 1;
00824 }
00825
QDir curDir(location() +
"/cur");
00826 curDir.setFilter(QDir::Files);
00827
00828
00829
const QFileInfoList *list = curDir.entryInfoList();
00830 QFileInfoListIterator it(*list);
00831
QFileInfo *fi;
00832
00833
while ((fi = it.current()))
00834 {
00835 readFileHeaderIntern(curDir.path(), fi->fileName(), KMMsgStatusRead);
00836 ++it;
00837 }
00838
00839
00840 list = newDir.entryInfoList();
00841 it = *list;
00842
00843
while ((fi=it.current()))
00844 {
00845 readFileHeaderIntern(newDir.path(), fi->fileName(), KMMsgStatusNew);
00846 ++it;
00847 }
00848
00849
if (autoCreateIndex())
00850 {
00851 emit statusMsg(i18n(
"Writing index file"));
00852 writeIndex();
00853 }
00854
else mHeaderOffset = 0;
00855
00856 correctUnreadMsgsCount();
00857
00858
if (kmkernel->outboxFolder() == folder() && count() > 0)
00859 KMessageBox::information(0, i18n(
"Your outbox contains messages which were "
00860
"most-likely not created by KMail;\nplease remove them from there if you "
00861
"do not want KMail to send them."));
00862
00863 needsCompact =
true;
00864
00865
if (folder()->parent())
00866 folder()->parent()->manager()->invalidateFolder(kmkernel->msgDict(), folder());
00867
return 0;
00868 }
00869
00870 KMFolderIndex::IndexStatus KMFolderMaildir::indexStatus()
00871 {
00872
QFileInfo new_info(location() +
"/new");
00873
QFileInfo cur_info(location() +
"/cur");
00874
QFileInfo index_info(indexLocation());
00875
00876
if (!index_info.exists())
00877
return KMFolderIndex::IndexMissing;
00878
00879
00880
00881
00882
return ((new_info.lastModified() > index_info.lastModified().addSecs(5)) ||
00883 (cur_info.lastModified() > index_info.lastModified().addSecs(5)))
00884 ? KMFolderIndex::IndexTooOld
00885 : KMFolderIndex::IndexOk;
00886 }
00887
00888
00889
void KMFolderMaildir::removeMsg(
int idx,
bool)
00890 {
00891 KMMsgBase* msg = mMsgList[idx];
00892
if (!msg || !msg->fileName())
return;
00893
00894 removeFile(msg->fileName());
00895
00896 KMFolderIndex::removeMsg(idx);
00897 }
00898
00899
00900 KMMessage* KMFolderMaildir::take(
int idx)
00901 {
00902
00903 KMMessage *msg = KMFolderIndex::take(idx);
00904
00905
if (!msg || !msg->fileName())
return 0;
00906
00907
if (removeFile(msg->fileName()))
00908
return msg;
00909
else
00910
return 0;
00911 }
00912
00913
bool KMFolderMaildir::removeFile(
const QString& filename)
00914 {
00915
00916
00917
00918
00919
QCString abs_file(QFile::encodeName(location() +
"/cur/"));
00920 abs_file += QFile::encodeName(filename);
00921
00922
if (::unlink( abs_file ) == 0)
00923
return true;
00924
00925
if (errno == ENOENT) {
00926
00927 abs_file = QFile::encodeName(location() +
"/new/");
00928 abs_file += QFile::encodeName(filename);
00929
00930
if (::unlink( abs_file ) == 0)
00931
return true;
00932
00933 }
00934
00935 kdDebug(5006) <<
"Can't delete " << abs_file <<
" " << perror << endl;
00936
return false;
00937 }
00938
00939
00940
int KMFolderMaildir::removeContents()
00941 {
00942
if (!KIO::NetAccess::del(KURL::fromPathOrURL(location()+
"/new/"), 0))
00943
return 1;
00944
if (!KIO::NetAccess::del(KURL::fromPathOrURL(location()+
"/cur/"), 0))
00945
return 1;
00946
if (!KIO::NetAccess::del(KURL::fromPathOrURL(location()+
"/tmp/"), 0))
00947
return 1;
00948
00949
00950
00951
00952
QDir dir(location());
00953
if ( dir.count() == 2 ) {
00954
if (!KIO::NetAccess::del(KURL::fromPathOrURL(location()), 0))
00955
return 1;
00956 }
00957
return 0;
00958 }
00959
00960
static QRegExp *suffix_regex = 0;
00961
static KStaticDeleter<QRegExp> suffix_regex_sd;
00962
00963
00964
QString KMFolderMaildir::constructValidFileName(
QString& aFileName, KMMsgStatus status)
00965 {
00966
if (aFileName.isEmpty())
00967 {
00968 aFileName.sprintf(
"%ld.%d.", (
long)time(0), getpid());
00969 aFileName += KApplication::randomString(5);
00970 }
00971
00972
if (!suffix_regex)
00973 suffix_regex_sd.setObject(suffix_regex,
new QRegExp(
":2,?R?S?$"));
00974
00975 aFileName.truncate(aFileName.findRev(*suffix_regex));
00976
00977
QString suffix;
00978
if (! ((status & KMMsgStatusNew) || (status & KMMsgStatusUnread)) )
00979 {
00980 suffix +=
":2,";
00981
if (status & KMMsgStatusReplied)
00982 suffix +=
"RS";
00983
else
00984 suffix +=
"S";
00985 }
00986
00987 aFileName += suffix;
00988
00989
return aFileName;
00990 }
00991
00992
00993
QString KMFolderMaildir::moveInternal(
const QString& oldLoc,
const QString& newLoc, KMMsgInfo *mi)
00994 {
00995
QString filename(mi->fileName());
00996
QString ret(moveInternal(oldLoc, newLoc, filename, mi->status()));
00997
00998
if (filename != mi->fileName())
00999 mi->setFileName(filename);
01000
01001
return ret;
01002 }
01003
01004
01005
QString KMFolderMaildir::moveInternal(
const QString& oldLoc,
const QString& newLoc,
QString& aFileName, KMMsgStatus status)
01006 {
01007
QString dest(newLoc);
01008
01009
while (QFile::exists(dest))
01010 {
01011 aFileName =
"";
01012 constructValidFileName(aFileName, status);
01013
01014
QFileInfo fi(dest);
01015 dest = fi.dirPath(
true) +
"/" + aFileName;
01016 setDirty(
true );
01017 }
01018
01019
QDir d;
01020
if (d.rename(oldLoc, dest) ==
false)
01021
return QString::null;
01022
else
01023
return dest;
01024 }
01025
01026
01027
void KMFolderMaildir::msgStatusChanged(
const KMMsgStatus oldStatus,
01028
const KMMsgStatus newStatus,
int idx)
01029 {
01030
01031 needsCompact =
true;
01032
01033 KMFolderIndex::msgStatusChanged(oldStatus, newStatus, idx);
01034 }
01035
01036
#include "kmfoldermaildir.moc"