21 #include <tqfileinfo.h>
24 #include "kmfoldermbox.h"
25 #include "folderstorage.h"
28 #include "kmmsgdict.h"
29 #include "undostack.h"
30 #include "kcursorsaver.h"
31 #include "jobscheduler.h"
32 #include "compactionjob.h"
36 #include <tdelocale.h>
37 #include <tdemessagebox.h>
38 #include <knotifyclient.h>
39 #include <tdeprocess.h>
40 #include <tdeconfig.h>
52 #include <sys/types.h>
55 #include "broadcaststatus.h"
56 using KPIM::BroadcastStatus;
67 #define MSG_SEPERATOR_START "From "
68 #define MSG_SEPERATOR_START_LEN (sizeof(MSG_SEPERATOR_START) - 1)
69 #define MSG_SEPERATOR_REGEX "^From .*[0-9][0-9]:[0-9][0-9]"
73 KMFolderMbox::KMFolderMbox(
KMFolder* folder,
const char* name)
79 mLockType = lock_none;
84 KMFolderMbox::~KMFolderMbox()
87 close(
"~kmfoldermbox",
true);
88 if (kmkernel->undoStack())
89 kmkernel->undoStack()->folderDestroyed( folder() );
93 int KMFolderMbox::open(
const char *owner)
99 kmkernel->jobScheduler()->notifyOpeningFolder( folder() );
101 if (mOpenCount > 1)
return 0;
103 assert(!folder()->name().isEmpty());
105 mFilesLocked =
false;
106 mStream = fopen(TQFile::encodeName(location()),
"r+");
109 KNotifyClient::event( 0,
"warning",
110 i18n(
"Cannot open file \"%1\":\n%2").arg(location()).arg(strerror(errno)));
111 kdDebug(5006) <<
"Cannot open folder `" << location() <<
"': " << strerror(errno) << endl;
118 if (!folder()->path().isEmpty())
122 if (KMFolderIndex::IndexOk != index_status)
126 if (KMFolderIndex::IndexTooOld == index_status) {
127 TQString msg = i18n(
"<qt><p>The index of folder '%2' seems "
128 "to be out of date. To prevent message "
129 "corruption the index will be "
130 "regenerated. As a result deleted "
131 "messages might reappear and status "
132 "flags might be lost.</p>"
133 "<p>Please read the corresponding entry "
134 "in the <a href=\"%1\">FAQ section of the manual "
136 "information about how to prevent this "
137 "problem from happening again.</p></qt>")
138 .arg(
"help:/kmail/faq.html#faq-index-regeneration")
144 if (kmkernel->startingUp())
146 TDEConfigGroup configGroup( KMKernel::config(),
"Notification Messages" );
148 configGroup.readBoolEntry(
"showIndexRegenerationMessage",
true );
150 KMessageBox::queuedMessageBox( 0, KMessageBox::Information,
151 msg, i18n(
"Index Out of Date"),
152 KMessageBox::AllowLink );
157 KMessageBox::information( 0, msg, i18n(
"Index Out of Date"),
158 "showIndexRegenerationMessage",
159 KMessageBox::AllowLink );
164 str = i18n(
"Folder `%1' changed. Recreating index.")
168 mIndexStream = fopen(TQFile::encodeName(indexLocation()),
"r+");
169 if ( mIndexStream ) {
170 fcntl(fileno(mIndexStream), F_SETFD, FD_CLOEXEC);
171 updateIndexStreamPtr();
176 rc = createIndexFromContents();
179 rc = createIndexFromContents();
183 mAutoCreateIndex =
false;
184 rc = createIndexFromContents();
189 fcntl(fileno(mStream), F_SETFD, FD_CLOEXEC);
191 fcntl(fileno(mIndexStream), F_SETFD, FD_CLOEXEC);
197 int KMFolderMbox::canAccess()
199 assert(!folder()->name().isEmpty());
201 if (access(TQFile::encodeName(location()), R_OK | W_OK) != 0) {
202 kdDebug(5006) <<
"KMFolderMbox::access call to access function failed" << endl;
209 int KMFolderMbox::create()
214 assert(!folder()->name().isEmpty());
215 assert(mOpenCount == 0);
217 kdDebug(5006) <<
"Creating folder " << name() << endl;
218 if (access(TQFile::encodeName(location()), F_OK) == 0) {
219 kdDebug(5006) <<
"KMFolderMbox::create call to access function failed." << endl;
220 kdDebug(5006) <<
"File:: " << endl;
221 kdDebug(5006) <<
"Error " << endl;
225 old_umask = umask(077);
226 mStream = fopen(TQFile::encodeName(location()),
"w+");
229 if (!mStream)
return errno;
231 fcntl(fileno(mStream), F_SETFD, FD_CLOEXEC);
233 if (!folder()->path().isEmpty())
235 old_umask = umask(077);
236 mIndexStream = fopen(TQFile::encodeName(indexLocation()),
"w+");
237 updateIndexStreamPtr(
true);
240 if (!mIndexStream)
return errno;
241 fcntl(fileno(mIndexStream), F_SETFD, FD_CLOEXEC);
245 mAutoCreateIndex =
false;
258 void KMFolderMbox::reallyDoClose(
const char* owner)
261 if (mAutoCreateIndex)
263 if (KMFolderIndex::IndexOk != indexStatus()) {
264 kdDebug(5006) <<
"Critical error: " << location() <<
265 " has been modified by an external application while KMail was running." << endl;
274 if (mStream) unlock();
275 mMsgList.clear(
true);
277 if (mStream) fclose(mStream);
279 fclose(mIndexStream);
280 updateIndexStreamPtr(
true);
286 mFilesLocked =
false;
289 mMsgList.reset(INIT_MSGS);
293 void KMFolderMbox::sync()
296 if (!mStream || fsync(fileno(mStream)) ||
297 !mIndexStream || fsync(fileno(mIndexStream))) {
298 kmkernel->emergencyExit( i18n(
"Could not sync index file <b>%1</b>: %2").arg( indexLocation() ).arg(errno ? TQString::fromLocal8Bit(strerror(errno)) : i18n(
"Internal error. Please copy down the details and report a bug.")));
303 int KMFolderMbox::lock()
313 assert(mStream != 0);
314 mFilesLocked =
false;
320 rc = fcntl(fileno(mStream), F_SETLKW, &fl);
324 kdDebug(5006) <<
"Cannot lock folder `" << location() <<
"': "
325 << strerror(errno) <<
" (" << errno <<
")" << endl;
332 rc = fcntl(fileno(mIndexStream), F_SETLK, &fl);
336 kdDebug(5006) <<
"Cannot lock index of folder `" << location() <<
"': "
337 << strerror(errno) <<
" (" << errno <<
")" << endl;
340 fcntl(fileno(mIndexStream), F_SETLK, &fl);
347 case procmail_lockfile:
348 cmd_str =
"lockfile -l20 -r5 ";
349 if (!mProcmailLockFileName.isEmpty())
350 cmd_str += TQFile::encodeName(TDEProcess::quote(mProcmailLockFileName));
352 cmd_str += TQFile::encodeName(TDEProcess::quote(location() +
".lock"));
354 rc = system( cmd_str.data() );
357 kdDebug(5006) <<
"Cannot lock folder `" << location() <<
"': "
358 << strerror(rc) <<
" (" << rc <<
")" << endl;
364 cmd_str =
"lockfile -l20 -r5 " + TQFile::encodeName(TDEProcess::quote(indexLocation() +
".lock"));
365 rc = system( cmd_str.data() );
368 kdDebug(5006) <<
"Cannot lock index of folder `" << location() <<
"': "
369 << strerror(rc) <<
" (" << rc <<
")" << endl;
377 cmd_str =
"mutt_dotlock " + TQFile::encodeName(TDEProcess::quote(location()));
378 rc = system( cmd_str.data() );
381 kdDebug(5006) <<
"Cannot lock folder `" << location() <<
"': "
382 << strerror(rc) <<
" (" << rc <<
")" << endl;
388 cmd_str =
"mutt_dotlock " + TQFile::encodeName(TDEProcess::quote(indexLocation()));
389 rc = system( cmd_str.data() );
392 kdDebug(5006) <<
"Cannot lock index of folder `" << location() <<
"': "
393 << strerror(rc) <<
" (" << rc <<
")" << endl;
400 case mutt_dotlock_privileged:
401 cmd_str =
"mutt_dotlock -p " + TQFile::encodeName(TDEProcess::quote(location()));
402 rc = system( cmd_str.data() );
405 kdDebug(5006) <<
"Cannot lock folder `" << location() <<
"': "
406 << strerror(rc) <<
" (" << rc <<
")" << endl;
412 cmd_str =
"mutt_dotlock -p " + TQFile::encodeName(TDEProcess::quote(indexLocation()));
413 rc = system( cmd_str.data() );
416 kdDebug(5006) <<
"Cannot lock index of folder `" << location() <<
"': "
417 << strerror(rc) <<
" (" << rc <<
")" << endl;
436 KMFolderMbox::doCreateJob(
KMMessage *msg, FolderJob::JobType jt,
437 KMFolder *folder, TQString,
const AttachmentStrategy* )
const
439 MboxJob *job =
new MboxJob( msg, jt, folder );
440 job->setParent(
this );
446 KMFolderMbox::doCreateJob( TQPtrList<KMMessage>& msgList,
const TQString& sets,
447 FolderJob::JobType jt,
KMFolder *folder )
const
449 MboxJob *job =
new MboxJob( msgList, sets, jt, folder );
450 job->setParent(
this );
455 int KMFolderMbox::unlock()
465 assert(mStream != 0);
466 mFilesLocked =
false;
471 if (mIndexStream) fcntl(fileno(mIndexStream), F_SETLK, &fl);
472 fcntl(fileno(mStream), F_SETLK, &fl);
476 case procmail_lockfile:
478 if (!mProcmailLockFileName.isEmpty())
479 cmd_str += TQFile::encodeName(TDEProcess::quote(mProcmailLockFileName));
481 cmd_str += TQFile::encodeName(TDEProcess::quote(location() +
".lock"));
483 rc = system( cmd_str.data() );
486 cmd_str =
"rm -f " + TQFile::encodeName(TDEProcess::quote(indexLocation() +
".lock"));
487 rc = system( cmd_str.data() );
492 cmd_str =
"mutt_dotlock -u " + TQFile::encodeName(TDEProcess::quote(location()));
493 rc = system( cmd_str.data() );
496 cmd_str =
"mutt_dotlock -u " + TQFile::encodeName(TDEProcess::quote(indexLocation()));
497 rc = system( cmd_str.data() );
501 case mutt_dotlock_privileged:
502 cmd_str =
"mutt_dotlock -p -u " + TQFile::encodeName(TDEProcess::quote(location()));
503 rc = system( cmd_str.data() );
506 cmd_str =
"mutt_dotlock -p -u " + TQFile::encodeName(TDEProcess::quote(indexLocation()));
507 rc = system( cmd_str.data() );
525 return KMFolderIndex::IndexCorrupt;
527 TQFileInfo contInfo(location());
528 TQFileInfo indInfo(indexLocation());
530 if (!contInfo.exists())
return KMFolderIndex::IndexOk;
531 if (!indInfo.exists())
return KMFolderIndex::IndexMissing;
536 return ( contInfo.lastModified() > indInfo.lastModified().addSecs(5) )
537 ? KMFolderIndex::IndexTooOld
538 : KMFolderIndex::IndexOk;
543 int KMFolderMbox::createIndexFromContents()
546 char status[8], xstatus[8];
547 TQCString subjStr, dateStr, fromStr, toStr, xmarkStr, *lastStr=0;
548 TQCString replyToIdStr, replyToAuxIdStr, referencesStr, msgIdStr;
549 TQCString sizeServerStr, uidStr;
550 TQCString contentTypeStr, charset;
552 bool inHeader =
true;
555 TQRegExp regexp(MSG_SEPERATOR_REGEX);
556 int i, num, numStatus;
559 assert(mStream != 0);
576 replyToAuxIdStr =
"";
580 size_t sizeServer = 0;
586 off_t pos = ftell(mStream);
587 if (!fgets(line, MAX_LINE, mStream)) atEof =
true;
590 (memcmp(line, MSG_SEPERATOR_START, MSG_SEPERATOR_START_LEN)==0 &&
591 regexp.search(line) >= 0))
594 pos = ftell(mStream);
600 msgStr = i18n(
"Creating index file: one message done",
"Creating index file: %n messages done", num);
601 emit statusMsg(msgStr);
607 msgIdStr = msgIdStr.stripWhiteSpace();
608 if( !msgIdStr.isEmpty() ) {
610 rightAngle = msgIdStr.find(
'>' );
611 if( rightAngle != -1 )
612 msgIdStr.truncate( rightAngle + 1 );
615 replyToIdStr = replyToIdStr.stripWhiteSpace();
616 if( !replyToIdStr.isEmpty() ) {
618 rightAngle = replyToIdStr.find(
'>' );
619 if( rightAngle != -1 )
620 replyToIdStr.truncate( rightAngle + 1 );
623 referencesStr = referencesStr.stripWhiteSpace();
624 if( !referencesStr.isEmpty() ) {
625 int leftAngle, rightAngle;
626 leftAngle = referencesStr.findRev(
'<' );
627 if( ( leftAngle != -1 )
628 && ( replyToIdStr.isEmpty() || ( replyToIdStr[0] !=
'<' ) ) ) {
630 replyToIdStr = referencesStr.mid( leftAngle );
634 leftAngle = referencesStr.findRev(
'<', leftAngle - 1 );
635 if( leftAngle != -1 )
636 referencesStr = referencesStr.mid( leftAngle );
637 rightAngle = referencesStr.findRev(
'>' );
638 if( rightAngle != -1 )
639 referencesStr.truncate( rightAngle + 1 );
645 replyToAuxIdStr = referencesStr;
646 rightAngle = referencesStr.find(
'>' );
647 if( rightAngle != -1 )
648 replyToAuxIdStr.truncate( rightAngle + 1 );
651 contentTypeStr = contentTypeStr.stripWhiteSpace();
653 if ( !contentTypeStr.isEmpty() )
655 int cidx = contentTypeStr.find(
"charset=" );
657 charset = contentTypeStr.mid( cidx + 8 );
658 if ( !charset.isEmpty() && ( charset[0] ==
'"' ) ) {
659 charset = charset.mid( 1 );
662 while ( (
unsigned int) cidx < charset.length() ) {
663 if ( charset[cidx] ==
'"' || ( !isalnum(charset[cidx]) &&
664 charset[cidx] !=
'-' && charset[cidx] !=
'_' ) )
668 charset.truncate( cidx );
674 mi =
new KMMsgInfo(folder());
675 mi->init( subjStr.stripWhiteSpace(),
676 fromStr.stripWhiteSpace(),
677 toStr.stripWhiteSpace(),
679 xmarkStr.stripWhiteSpace(),
680 replyToIdStr, replyToAuxIdStr, msgIdStr,
681 KMMsgEncryptionStateUnknown, KMMsgSignatureStateUnknown,
682 KMMsgMDNStateUnknown, charset, offs, size, sizeServer, uid );
683 mi->setStatus(status, xstatus);
684 mi->setDate( dateStr.stripWhiteSpace().data() );
686 mMsgList.append(mi, mExportsSernums );
693 replyToAuxIdStr =
"";
702 else num--,numStatus++;
705 offs = ftell(mStream);
712 if (inHeader && (line[0]==
'\t' || line[0]==
' '))
715 while (line [i]==
'\t' || line [i]==
' ') i++;
716 if (line [i] <
' ' && line [i]>0) inHeader =
false;
717 else if (lastStr) *lastStr += line + i;
721 if (inHeader && (line [0]==
'\n' || line [0]==
'\r'))
723 if (!inHeader)
continue;
728 if ((needStatus & 1) && strncasecmp(line,
"Status:", 7) == 0)
730 for(i=0; i<4 && line[i+8] >
' '; i++)
731 status[i] = line[i+8];
735 else if ((needStatus & 2) && strncasecmp(line,
"X-Status:", 9)==0)
737 for(i=0; i<4 && line[i+10] >
' '; i++)
738 xstatus[i] = line[i+10];
742 else if (strncasecmp(line,
"X-KMail-Mark:",13)==0)
743 xmarkStr = TQCString(line+13);
744 else if (strncasecmp(line,
"In-Reply-To:",12)==0) {
745 replyToIdStr = TQCString(line+12);
746 lastStr = &replyToIdStr;
748 else if (strncasecmp(line,
"References:",11)==0) {
749 referencesStr = TQCString(line+11);
750 lastStr = &referencesStr;
752 else if (strncasecmp(line,
"Message-Id:",11)==0) {
753 msgIdStr = TQCString(line+11);
756 else if (strncasecmp(line,
"Date:",5)==0)
758 dateStr = TQCString(line+5);
761 else if (strncasecmp(line,
"From:", 5)==0)
763 fromStr = TQCString(line+5);
766 else if (strncasecmp(line,
"To:", 3)==0)
768 toStr = TQCString(line+3);
771 else if (strncasecmp(line,
"Subject:",8)==0)
773 subjStr = TQCString(line+8);
776 else if (strncasecmp(line,
"X-Length:",9)==0)
778 sizeServerStr = TQCString(line+9);
779 sizeServer = sizeServerStr.toULong();
780 lastStr = &sizeServerStr;
782 else if (strncasecmp(line,
"X-UID:",6)==0)
784 uidStr = TQCString(line+6);
785 uid = uidStr.toULong();
788 else if (strncasecmp(line,
"Content-Type:", 13) == 0)
790 contentTypeStr = TQCString(line+13);
791 lastStr = &contentTypeStr;
795 if (mAutoCreateIndex)
797 emit statusMsg(i18n(
"Writing index file"));
800 else mHeaderOffset = 0;
802 correctUnreadMsgsCount();
804 if (kmkernel->outboxFolder() == folder() && count() > 0)
805 KMessageBox::queuedMessageBox(0, KMessageBox::Information,
806 i18n(
"Your outbox contains messages which were "
807 "most-likely not created by KMail;\nplease remove them from there if you "
808 "do not want KMail to send them."));
816 KMMessage* KMFolderMbox::readMsg(
int idx)
818 KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
820 assert(mi!=0 && !mi->isMessage());
821 assert(mStream != 0);
831 #define STRDIM(x) (sizeof(x)/sizeof(*x)-1)
833 static size_t unescapeFrom(
char* str,
size_t strLen ) {
836 if ( strLen <= STRDIM(
">From ") )
843 const char * s = str;
845 const char *
const e = str + strLen - STRDIM(
">From ");
848 if ( *s ==
'\n' && *(s+1) ==
'>' ) {
851 while ( s < e && *s == '>
' )
853 if ( tqstrncmp( s, "From ", STRDIM("From ") ) == 0 )
856 *d++ = *s++; // yes, s might be e here, but e is not the end :-)
859 while ( s < str + strLen )
861 if ( d < s ) // only NUL-terminate if it's shorter
868 TQByteArray KMFolderMbox::escapeFrom(
const DwString & str ) {
869 const unsigned int strLen = str.length();
870 if ( strLen <= STRDIM(
"From ") )
873 TQByteArray result(
int( strLen + 5 ) / 6 * 7 + 1 );
875 const char * s = str.data();
876 const char *
const e = s + strLen - STRDIM(
"From ");
877 char * d = result.data();
879 bool onlyAnglesAfterLF =
false;
883 onlyAnglesAfterLF =
true;
888 if ( onlyAnglesAfterLF && tqstrncmp( s+1,
"rom ", STRDIM(
"rom ") ) == 0 )
892 onlyAnglesAfterLF =
false;
897 while ( s < str.data() + strLen )
900 result.truncate( d - result.data() );
907 DwString KMFolderMbox::getDwString(
int idx)
909 KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
912 assert(mStream != 0);
914 size_t msgSize = mi->msgSize();
915 char* msgText =
new char[ msgSize + 1 ];
917 fseek(mStream, mi->folderOffset(), SEEK_SET);
918 fread(msgText, msgSize, 1, mStream);
919 msgText[msgSize] =
'\0';
921 size_t newMsgSize = unescapeFrom( msgText, msgSize );
926 msgStr.TakeBuffer( msgText, msgSize + 1, 0, newMsgSize );
934 if (!canAddMsgNow(aMsg, aIndex_ret))
return 0;
939 bool editing =
false;
943 rc = openThis.openResult();
946 kdDebug(5006) <<
"KMFolderMbox::addMsg-open: " << rc <<
" of folder: " << label() << endl;
951 msgParent = aMsg->parent();
954 if ( msgParent== folder() )
956 if (kmkernel->folderIsDraftOrOutbox( folder() ))
959 kdDebug(5006) <<
"Editing message in outbox or drafts" << endl;
966 idx = msgParent->
find(aMsg);
970 if (folderType() != KMFolderTypeImap)
993 size_t len = msgText.size();
995 assert(mStream != 0);
999 kdDebug(5006) <<
"Message added to folder `" << name() <<
"' contains no data. Ignoring it." << endl;
1005 fseek(mStream, 0, SEEK_END);
1006 off_t revert = ftell(mStream);
1007 if (ftell(mStream) >= 2) {
1009 fseek(mStream, -2, SEEK_END);
1010 fread(endStr, 1, 2, mStream);
1011 if (ftell(mStream) > 0 && endStr[0]!=
'\n') {
1013 if (endStr[1]!=
'\n') {
1015 fwrite(
"\n\n", 1, 2, mStream);
1018 else fwrite(
"\n", 1, 1, mStream);
1021 fseek(mStream,0,SEEK_END);
1022 int error = ferror(mStream);
1027 fwrite( messageSeparator.data(), messageSeparator.length(), 1, mStream );
1028 off_t offs = ftell(mStream);
1029 fwrite(msgText.data(), len, 1, mStream);
1030 if (msgText[(
int)len-1]!=
'\n') fwrite(
"\n\n", 1, 2, mStream);
1032 size_t size = ftell(mStream) - offs;
1034 error = ferror(mStream);
1036 kdDebug(5006) <<
"Error: Could not add message to folder: " << strerror(errno) << endl;
1037 if (ftell(mStream) > revert) {
1038 kdDebug(5006) <<
"Undoing changes" << endl;
1039 truncate( TQFile::encodeName(location()), revert );
1041 kmkernel->emergencyExit( i18n(
"Could not add message to folder: ") + TQString::fromLocal8Bit(strerror(errno)));
1057 if (idx >= 0) msgParent->
take(idx);
1061 if (aMsg->isUnread() || aMsg->isNew() ||
1062 (folder() == kmkernel->outboxFolder())) {
1063 if (mUnreadMsgs == -1) mUnreadMsgs = 1;
1066 emit numUnreadMsgsChanged( folder() );
1071 if ( aMsg->attachmentState() == KMMsgAttachmentUnknown && aMsg->
readyToShow() ) {
1072 aMsg->updateAttachmentState();
1074 if ( aMsg->invitationState() == KMMsgInvitationUnknown && aMsg->
readyToShow() ) {
1075 aMsg->updateInvitationState();
1079 aMsg->setParent(folder());
1080 aMsg->setFolderOffset(offs);
1081 aMsg->setMsgSize(size);
1082 idx = mMsgList.append(&aMsg->
toMsgBase(), mExportsSernums );
1083 if ( aMsg->getMsgSerNum() <= 0 )
1086 replaceMsgSerNum( aMsg->getMsgSerNum(), &aMsg->
toMsgBase(), idx );
1089 if ((idx > 0) && (growth > 0)) {
1091 if ((ulong)revert == mMsgList[idx - 1]->folderOffset() + mMsgList[idx - 1]->msgSize() )
1092 mMsgList[idx - 1]->setMsgSize( mMsgList[idx - 1]->msgSize() + growth );
1096 if (mAutoCreateIndex)
1098 assert(mIndexStream != 0);
1099 clearerr(mIndexStream);
1100 fseek(mIndexStream, 0, SEEK_END);
1101 revert = ftell(mIndexStream);
1105 const uchar *buffer = mb->asIndexString(len);
1106 fwrite(&len,
sizeof(len), 1, mIndexStream);
1107 mb->setIndexOffset( ftell(mIndexStream) );
1108 mb->setIndexLength( len );
1109 if(fwrite(buffer, len, 1, mIndexStream) != 1)
1110 kdDebug(5006) <<
"Whoa! " << __FILE__ <<
":" << __LINE__ << endl;
1112 fflush(mIndexStream);
1113 error = ferror(mIndexStream);
1115 if ( mExportsSernums )
1116 error |= appendToFolderIdsFile( idx );
1119 kdWarning(5006) <<
"Error: Could not add message to folder (No space left on device?)" << endl;
1120 if (ftell(mIndexStream) > revert) {
1121 kdWarning(5006) <<
"Undoing changes" << endl;
1122 truncate( TQFile::encodeName(indexLocation()), revert );
1125 kmkernel->emergencyExit( i18n(
"Could not add message to folder:") + TQString::fromLocal8Bit(strerror(errno)));
1127 kmkernel->emergencyExit( i18n(
"Could not add message to folder (No space left on device?)") );
1142 if (aIndex_ret) *aIndex_ret = idx;
1143 emitMsgAddedSignals(idx);
1151 int KMFolderMbox::compact(
unsigned int startIndex,
int nbMessages, FILE* tmpfile, off_t& offs,
bool& done )
1155 unsigned int stopIndex = nbMessages == -1 ? mMsgList.count() :
1156 TQMIN( mMsgList.count(), startIndex + nbMessages );
1158 for(
unsigned int idx = startIndex; idx < stopIndex; ++idx) {
1159 KMMsgInfo* mi = (KMMsgInfo*)mMsgList.at(idx);
1160 size_t msize = mi->msgSize();
1161 if (mtext.size() < msize + 2)
1162 mtext.resize(msize+2);
1163 off_t folder_offset = mi->folderOffset();
1166 for(off_t i = folder_offset-25;
true; i -= 20) {
1167 off_t chunk_offset = i <= 0 ? 0 : i;
1168 if(fseek(mStream, chunk_offset, SEEK_SET) == -1) {
1172 if (mtext.size() < 20)
1174 fread(mtext.data(), 20, 1, mStream);
1176 if ( mtext.contains(
"from ",
false ) ) {
1177 if (mtext.size() < (
size_t)folder_offset)
1178 mtext.resize(folder_offset);
1179 if(fseek(mStream, chunk_offset, SEEK_SET) == -1 ||
1180 !fread(mtext.data(), folder_offset, 1, mStream) ||
1181 !fwrite(mtext.data(), folder_offset, 1, tmpfile)) {
1185 offs += folder_offset;
1192 for(
int i2 = 0; i2 < 20; i2++) {
1193 if(*(mtext.data()+i2) ==
'\n')
1196 if(last_crlf != -1) {
1197 int size = folder_offset - (i + last_crlf+1);
1198 if ((
int)mtext.size() < size)
1200 if(fseek(mStream, i + last_crlf+1, SEEK_SET) == -1 ||
1201 !fread(mtext.data(), size, 1, mStream) ||
1202 !fwrite(mtext.data(), size, 1, tmpfile)) {
1215 if(fseek(mStream, folder_offset, SEEK_SET) == -1 ||
1216 !fread(mtext.data(), msize, 1, mStream) || !fwrite(mtext.data(), msize, 1, tmpfile)) {
1220 mi->setFolderOffset(offs);
1223 done = ( !rc && stopIndex == mMsgList.count() );
1228 int KMFolderMbox::compact(
bool silent )
1234 int rc = job->executeNow( silent );
1239 TQString statusMsg = BroadcastStatus::instance()->statusMsg();
1241 BroadcastStatus::instance()->setStatusMsg( statusMsg );
1247 void KMFolderMbox::setLockType( LockType ltype )
1253 void KMFolderMbox::setProcmailLockFileName(
const TQString &fname )
1255 mProcmailLockFileName = fname;
1259 int KMFolderMbox::removeContents()
1262 rc = unlink(TQFile::encodeName(location()));
1267 int KMFolderMbox::expungeContents()
1270 if (truncate(TQFile::encodeName(location()), 0))
1277 TQ_INT64 KMFolderMbox::doFolderSize()
const
1279 TQFileInfo info( location() );
1280 return (TQ_INT64)(info.size());
1284 #include "kmfoldermbox.moc"
virtual int addMsg(TQPtrList< KMMessage > &, TQValueList< int > &index_return)
Adds the given messages to the folder.
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
A FolderStorage with an index for faster access to often used message properties.
IndexStatus
This enum indicates the status of the index file.
RAII for KMFolder::open() / close().
KMMessage * take(int idx)
Detach message from this folder.
KMMessage * getMsg(int idx)
Read message at given index.
int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
bool readyToShow() const
Return if the message is ready to be shown.
void setStatusFields()
Set "Status" and "X-Status" fields of the message from the internal message status.
void removeHeaderField(const TQCString &name)
Remove header field with given name.
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
const DwString & asDwString() const
Return the entire message contents in the DwString.
void setMsgSerNum(unsigned long newMsgSerNum=0)
Sets the message serial number.
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
TQCString mboxMessageSeparator()
Returns an mbox message separator line for this message, i.e.
KMMsgBase & toMsgBase()
Get KMMsgBase for this object.
void setMsgInfo(KMMsgInfo *msgInfo)
Set the KMMsgInfo object corresponding to this message.
A job that runs in the background and compacts mbox folders.
TQByteArray ByteArray(const DwString &str)
Construct a TQByteArray from a DwString.
size_t crlf2lf(char *str, const size_t strLen)
Convert all sequences of "\r\n" (carriage return followed by a line feed) to a single "\n" (line feed...