/kdepim-4.3.4/kmail/kmfoldermbox.cpp

# · C++ · 1369 lines · 1016 code · 145 blank · 208 comment · 249 complexity · ae77279a087f7080779649eb9d13e1ac MD5 · raw file

  1. /* -*- c-basic-offset: 2 -*-
  2. * kmail: KDE mail client
  3. * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. *
  19. */
  20. #include "kmfoldermbox.h"
  21. #include <config-kmail.h>
  22. #include <QFileInfo>
  23. #include <QList>
  24. #include <QRegExp>
  25. #include <QByteArray>
  26. #include "folderstorage.h"
  27. #include "kmfolder.h"
  28. #include "kmkernel.h"
  29. #include "kmmsgdict.h"
  30. #include "undostack.h"
  31. #include "kcursorsaver.h"
  32. #include "jobscheduler.h"
  33. #include "compactionjob.h"
  34. #include "util.h"
  35. #include <kde_file.h>
  36. #include <kdebug.h>
  37. #include <klocale.h>
  38. #include <kmessagebox.h>
  39. #include <knotification.h>
  40. #include <kshell.h>
  41. #include <kconfig.h>
  42. #include <kconfiggroup.h>
  43. #include <QDateTime>
  44. #include <stdio.h>
  45. #include <errno.h>
  46. #include <assert.h>
  47. #include <unistd.h>
  48. #ifdef HAVE_FCNTL_H
  49. #include <fcntl.h>
  50. #endif
  51. #include <stdlib.h>
  52. #include <sys/types.h>
  53. #include <sys/stat.h>
  54. #include <sys/file.h>
  55. #include "broadcaststatus.h"
  56. using KPIM::BroadcastStatus;
  57. #ifndef MAX_LINE
  58. #define MAX_LINE 4096
  59. #endif
  60. #ifndef INIT_MSGS
  61. #define INIT_MSGS 8
  62. #endif
  63. // Regular expression to find the line that separates messages in a mail
  64. // folder:
  65. #define MSG_SEPERATOR_START "From "
  66. #define MSG_SEPERATOR_START_LEN (sizeof(MSG_SEPERATOR_START) - 1)
  67. #define MSG_SEPERATOR_REGEX "^From .*[0-9][0-9]:[0-9][0-9]"
  68. #ifdef KMAIL_SQLITE_INDEX
  69. #include <sqlite3.h>
  70. #endif
  71. //-----------------------------------------------------------------------------
  72. KMFolderMbox::KMFolderMbox(KMFolder* folder, const char* name)
  73. : KMFolderIndex(folder, name)
  74. {
  75. mStream = 0;
  76. mFilesLocked = false;
  77. mReadOnly = false;
  78. mLockType = lock_none;
  79. }
  80. //-----------------------------------------------------------------------------
  81. KMFolderMbox::~KMFolderMbox()
  82. {
  83. if ( mOpenCount > 0 ) {
  84. close( "~kmfoldermbox", true );
  85. }
  86. if ( kmkernel->undoStack() ) {
  87. kmkernel->undoStack()->folderDestroyed( folder() );
  88. }
  89. }
  90. //-----------------------------------------------------------------------------
  91. int KMFolderMbox::open( const char *owner )
  92. {
  93. #ifdef FOLDER_REFCOUNT_DEBUGGING
  94. mOwners.append( owner );
  95. kDebug() << endl << "open" << mOpenCount << folder()->name()
  96. << mOwners << ", adding:" << owner;
  97. // << mOwners << ", adding:" << owner << kBacktrace();
  98. #else
  99. Q_UNUSED( owner );
  100. #endif
  101. int rc = 0;
  102. mOpenCount++;
  103. kmkernel->jobScheduler()->notifyOpeningFolder( folder() );
  104. if ( mOpenCount > 1 ) {
  105. return 0; // already open
  106. }
  107. assert( !folder()->name().isEmpty() );
  108. mFilesLocked = false;
  109. mStream = KDE_fopen( QFile::encodeName( location() ), "rb+" ); // messages file
  110. if ( !mStream ) {
  111. KMessageBox::sorry( 0, i18n( "Cannot open file \"%1\":\n%2",
  112. location(), strerror( errno ) ) );
  113. kDebug() << "Cannot open folder `" << location() <<"':" << strerror(errno);
  114. mOpenCount = 0;
  115. return errno;
  116. }
  117. lock();
  118. rc = openInternal( CheckIfIndexTooOld | CreateIndexFromContentsWhenReadIndexFailed );
  119. /* moved to openInternal()
  120. if ( !folder()->path().isEmpty() ) {
  121. KMFolderIndex::IndexStatus index_status = indexStatus();
  122. bool shouldCreateIndexFromContents = false;
  123. // test if index file exists and is up-to-date
  124. if ( KMFolderIndex::IndexOk != index_status ) {
  125. // only show a warning if the index file exists, otherwise it can be
  126. // silently regenerated
  127. if ( KMFolderIndex::IndexTooOld == index_status ) {
  128. QString msg = i18n("<qt><p>The index of folder '%2' seems "
  129. "to be out of date. To prevent message "
  130. "corruption the index will be "
  131. "regenerated. As a result deleted "
  132. "messages might reappear and status "
  133. "flags might be lost.</p>"
  134. "<p>Please read the corresponding entry "
  135. "in the <a href=\"%1\">FAQ section of the manual "
  136. "of KMail</a> for "
  137. "information about how to prevent this "
  138. "problem from happening again.</p></qt>",
  139. QString("help:/kmail/faq.html#faq-index-regeneration"),
  140. objectName());
  141. // When KMail is starting up we have to show a non-blocking message
  142. // box so that the initialization can continue. We don't show a
  143. // queued message box when KMail isn't starting up because queued
  144. // message boxes don't have a "Don't ask again" checkbox.
  145. if ( kmkernel->startingUp() ) {
  146. KConfigGroup configGroup( KMKernel::config(),
  147. "Notification Messages" );
  148. bool showMessage =
  149. configGroup.readEntry( "showIndexRegenerationMessage", true );
  150. if ( showMessage ) {
  151. KMessageBox::queuedMessageBox( 0, KMessageBox::Information,
  152. msg, i18n("Index Out of Date"),
  153. KMessageBox::AllowLink );
  154. }
  155. } else {
  156. KCursorSaver idle( KBusyPtr::idle() );
  157. KMessageBox::information( 0, msg, i18n("Index Out of Date"),
  158. "showIndexRegenerationMessage",
  159. KMessageBox::AllowLink );
  160. }
  161. }
  162. #ifdef KMAIL_SQLITE_INDEX
  163. #else
  164. mIndexStream = 0;
  165. #endif
  166. shouldCreateIndexFromContents = true;
  167. emit statusMsg( i18n("Folder `%1' changed. Recreating index.", objectName()) );
  168. } else {
  169. #ifdef KMAIL_SQLITE_INDEX
  170. #else
  171. mIndexStream = KDE_fopen( QFile::encodeName( indexLocation() ), "r+" ); // index file
  172. if ( mIndexStream ) {
  173. # ifndef Q_WS_WIN
  174. fcntl( fileno( mIndexStream ), F_SETFD, FD_CLOEXEC );
  175. # endif
  176. if ( !updateIndexStreamPtr() )
  177. return 1;
  178. }
  179. else
  180. shouldCreateIndexFromContents = true;
  181. #endif
  182. }
  183. if ( shouldCreateIndexFromContents ) {
  184. rc = createIndexFromContents();
  185. } else {
  186. if ( !readIndex() ) {
  187. rc = createIndexFromContents();
  188. }
  189. }
  190. } else {
  191. mAutoCreateIndex = false;
  192. rc = createIndexFromContents();
  193. }
  194. mChanged = false;*/
  195. #ifdef KMAIL_SQLITE_INDEX
  196. #else
  197. # ifndef Q_WS_WIN
  198. fcntl( fileno( mStream ), F_SETFD, FD_CLOEXEC );
  199. if ( mIndexStream ) {
  200. fcntl( fileno( mIndexStream ), F_SETFD, FD_CLOEXEC );
  201. }
  202. # endif
  203. #endif
  204. return rc;
  205. }
  206. //----------------------------------------------------------------------------
  207. bool KMFolderMbox::canAccess() const
  208. {
  209. assert(!folder()->name().isEmpty());
  210. QFileInfo finfo( location() );
  211. if ( !finfo.isReadable() || !finfo.isWritable() ) {
  212. kDebug() << "call to access function failed";
  213. return false;
  214. }
  215. return true;
  216. }
  217. //-----------------------------------------------------------------------------
  218. int KMFolderMbox::create()
  219. {
  220. int rc;
  221. int old_umask;
  222. assert(!folder()->name().isEmpty());
  223. assert(mOpenCount == 0);
  224. kDebug() << "Creating folder" << objectName();
  225. if (access(QFile::encodeName(location()), F_OK) == 0) {
  226. kDebug() << "call to access function failed.";
  227. kDebug() << "Error";
  228. return EEXIST;
  229. }
  230. old_umask = umask(077);
  231. mStream = KDE_fopen(QFile::encodeName(location()), "w+"); //sven; open RW
  232. umask(old_umask);
  233. if (!mStream) return errno;
  234. #ifndef Q_WS_WIN
  235. fcntl(fileno(mStream), F_SETFD, FD_CLOEXEC);
  236. #endif
  237. rc = createInternal();
  238. if (!rc)
  239. lock();
  240. return rc;
  241. }
  242. //-----------------------------------------------------------------------------
  243. void KMFolderMbox::reallyDoClose()
  244. {
  245. if ( mAutoCreateIndex ) {
  246. if ( KMFolderIndex::IndexOk != indexStatus() ) {
  247. kDebug() << "Critical error:" << location()
  248. << "has been modified by an external application while KMail was running.";
  249. // exit(1); backed out due to broken nfs
  250. }
  251. updateIndex( true );
  252. writeConfig();
  253. }
  254. if ( !noContent() ) {
  255. if ( mStream ) {
  256. unlock();
  257. }
  258. mMsgList.clear( true );
  259. if ( mStream ) {
  260. fclose( mStream );
  261. }
  262. #ifdef KMAIL_SQLITE_INDEX
  263. if ( mIndexDb )
  264. sqlite3_close( mIndexDb );
  265. #else
  266. if ( mIndexStream ) {
  267. fclose( mIndexStream );
  268. updateIndexStreamPtr( true );
  269. }
  270. #endif
  271. }
  272. #ifdef KMAIL_SQLITE_INDEX
  273. mIndexDb = 0;
  274. #else
  275. mIndexStream = 0;
  276. #endif
  277. mOpenCount = 0;
  278. mStream = 0;
  279. mFilesLocked = false;
  280. mUnreadMsgs = -1;
  281. mMsgList.reset( INIT_MSGS );
  282. }
  283. //-----------------------------------------------------------------------------
  284. void KMFolderMbox::sync()
  285. {
  286. #ifdef KMAIL_SQLITE_INDEX
  287. #else
  288. if (mOpenCount > 0)
  289. if (!mStream || fsync(fileno(mStream)) ||
  290. !mIndexStream || fsync(fileno(mIndexStream))) {
  291. kmkernel->emergencyExit( i18n("Could not sync index file <b>%1</b>: %2", indexLocation(), errno ? QString::fromLocal8Bit(strerror(errno)) : i18n("Internal error. Please copy down the details and report a bug.")));
  292. }
  293. #endif
  294. }
  295. //-----------------------------------------------------------------------------
  296. int KMFolderMbox::lock()
  297. {
  298. #ifdef Q_WS_WIN
  299. # ifdef __GNUC__
  300. # warning TODO implement mbox locking on Windows
  301. # else
  302. # pragma WARNING( TODO implement mbox locking on Windows )
  303. # endif
  304. assert(mStream != 0);
  305. mFilesLocked = true;
  306. mReadOnly = false;
  307. #else
  308. int rc;
  309. struct flock fl;
  310. fl.l_type=F_WRLCK;
  311. fl.l_whence=0;
  312. fl.l_start=0;
  313. fl.l_len=0;
  314. fl.l_pid=-1;
  315. QByteArray cmd_str;
  316. assert(mStream != 0);
  317. mFilesLocked = false;
  318. mReadOnly = false;
  319. switch( mLockType )
  320. {
  321. case FCNTL:
  322. rc = fcntl(fileno(mStream), F_SETLKW, &fl);
  323. if (rc < 0)
  324. {
  325. kDebug() << "Cannot lock folder `" << location() << "':"
  326. << strerror(errno) << "(" << errno << ")";
  327. mReadOnly = true;
  328. return errno;
  329. }
  330. #ifdef KMAIL_SQLITE_INDEX
  331. #else
  332. if (mIndexStream)
  333. {
  334. rc = fcntl(fileno(mIndexStream), F_SETLK, &fl);
  335. if (rc < 0)
  336. {
  337. kDebug() << "Cannot lock index of folder `" << location() << "':"
  338. << strerror(errno) << "(" << errno << ")";
  339. rc = errno;
  340. fl.l_type = F_UNLCK;
  341. /*rc =*/ fcntl(fileno(mIndexStream), F_SETLK, &fl);
  342. mReadOnly = true;
  343. return rc;
  344. }
  345. }
  346. #endif
  347. break;
  348. case procmail_lockfile:
  349. cmd_str = "lockfile -l20 -r5 ";
  350. if (!mProcmailLockFileName.isEmpty())
  351. cmd_str += QFile::encodeName(KShell::quoteArg(mProcmailLockFileName));
  352. else
  353. cmd_str += QFile::encodeName(KShell::quoteArg(location() + ".lock"));
  354. rc = system( cmd_str.data() );
  355. if( rc != 0 )
  356. {
  357. kDebug() << "Cannot lock folder `" << location() << "':"
  358. << strerror(rc) << "(" << rc << ")";
  359. mReadOnly = true;
  360. return rc;
  361. }
  362. #ifdef KMAIL_SQLITE_INDEX
  363. #else
  364. if( mIndexStream )
  365. {
  366. cmd_str = "lockfile -l20 -r5 " + QFile::encodeName(KShell::quoteArg(indexLocation() + ".lock"));
  367. rc = system( cmd_str.data() );
  368. if( rc != 0 )
  369. {
  370. kDebug() << "Cannot lock index of folder `" << location() << "':"
  371. << strerror(rc) << "(" << rc << ")";
  372. mReadOnly = true;
  373. return rc;
  374. }
  375. }
  376. #endif
  377. break;
  378. case mutt_dotlock:
  379. cmd_str = "mutt_dotlock " + QFile::encodeName(KShell::quoteArg(location()));
  380. rc = system( cmd_str.data() );
  381. if( rc != 0 )
  382. {
  383. kDebug() << "Cannot lock folder `" << location() << "':"
  384. << strerror(rc) << "(" << rc << ")";
  385. mReadOnly = true;
  386. return rc;
  387. }
  388. #ifdef KMAIL_SQLITE_INDEX
  389. #else
  390. if( mIndexStream )
  391. {
  392. cmd_str = "mutt_dotlock " + QFile::encodeName(KShell::quoteArg(indexLocation()));
  393. rc = system( cmd_str.data() );
  394. if( rc != 0 )
  395. {
  396. kDebug() << "Cannot lock index of folder `" << location() << "':"
  397. << strerror(rc) << "(" << rc << ")";
  398. mReadOnly = true;
  399. return rc;
  400. }
  401. }
  402. #endif
  403. break;
  404. case mutt_dotlock_privileged:
  405. cmd_str = "mutt_dotlock -p " + QFile::encodeName(KShell::quoteArg(location()));
  406. rc = system( cmd_str.data() );
  407. if( rc != 0 )
  408. {
  409. kDebug() << "Cannot lock folder `" << location() << "':"
  410. << strerror(rc) << "(" << rc << ")";
  411. mReadOnly = true;
  412. return rc;
  413. }
  414. #ifdef KMAIL_SQLITE_INDEX
  415. #else
  416. if( mIndexStream )
  417. {
  418. cmd_str = "mutt_dotlock -p " + QFile::encodeName(KShell::quoteArg(indexLocation()));
  419. rc = system( cmd_str.data() );
  420. if( rc != 0 )
  421. {
  422. kDebug() << "Cannot lock index of folder `" << location() << "':"
  423. << strerror(rc) << "(" << rc << ")";
  424. mReadOnly = true;
  425. return rc;
  426. }
  427. }
  428. #endif
  429. break;
  430. case lock_none:
  431. default:
  432. break;
  433. }
  434. mFilesLocked = true;
  435. #endif
  436. return 0;
  437. }
  438. //-------------------------------------------------------------
  439. FolderJob*
  440. KMFolderMbox::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
  441. KMFolder *folder, const QString&, const AttachmentStrategy* ) const
  442. {
  443. MboxJob *job = new MboxJob( msg, jt, folder );
  444. job->setParent( this );
  445. return job;
  446. }
  447. //-------------------------------------------------------------
  448. FolderJob*
  449. KMFolderMbox::doCreateJob( QList<KMMessage*>& msgList, const QString& sets,
  450. FolderJob::JobType jt, KMFolder *folder ) const
  451. {
  452. MboxJob *job = new MboxJob( msgList, sets, jt, folder );
  453. job->setParent( this );
  454. return job;
  455. }
  456. //-----------------------------------------------------------------------------
  457. int KMFolderMbox::unlock()
  458. {
  459. #ifdef Q_WS_WIN
  460. # ifdef __GNUC__
  461. # warning TODO implement mbox unlocking on Windows
  462. # else
  463. # pragma WARNING( TODO implement mbox unlocking on Windows )
  464. # endif
  465. mFilesLocked = false;
  466. return 0;
  467. #else
  468. int rc;
  469. struct flock fl;
  470. fl.l_type=F_UNLCK;
  471. fl.l_whence=0;
  472. fl.l_start=0;
  473. fl.l_len=0;
  474. QByteArray cmd_str;
  475. assert(mStream != 0);
  476. mFilesLocked = false;
  477. switch( mLockType )
  478. {
  479. case FCNTL:
  480. #ifdef KMAIL_SQLITE_INDEX
  481. #else
  482. if (mIndexStream)
  483. fcntl(fileno(mIndexStream), F_SETLK, &fl);
  484. #endif
  485. fcntl(fileno(mStream), F_SETLK, &fl);
  486. rc = errno;
  487. break;
  488. case procmail_lockfile:
  489. cmd_str = "rm -f ";
  490. if (!mProcmailLockFileName.isEmpty())
  491. cmd_str += QFile::encodeName(KShell::quoteArg(mProcmailLockFileName));
  492. else
  493. cmd_str += QFile::encodeName(KShell::quoteArg(location() + ".lock"));
  494. rc = system( cmd_str.data() );
  495. #ifdef KMAIL_SQLITE_INDEX
  496. #else
  497. if( mIndexStream )
  498. {
  499. cmd_str = "rm -f " + QFile::encodeName(KShell::quoteArg(indexLocation() + ".lock"));
  500. rc = system( cmd_str.data() );
  501. }
  502. #endif
  503. break;
  504. case mutt_dotlock:
  505. cmd_str = "mutt_dotlock -u " + QFile::encodeName(KShell::quoteArg(location()));
  506. rc = system( cmd_str.data() );
  507. #ifdef KMAIL_SQLITE_INDEX
  508. #else
  509. if( mIndexStream )
  510. {
  511. cmd_str = "mutt_dotlock -u " + QFile::encodeName(KShell::quoteArg(indexLocation()));
  512. rc = system( cmd_str.data() );
  513. }
  514. #endif
  515. break;
  516. case mutt_dotlock_privileged:
  517. cmd_str = "mutt_dotlock -p -u " + QFile::encodeName(KShell::quoteArg(location()));
  518. rc = system( cmd_str.data() );
  519. #ifdef KMAIL_SQLITE_INDEX
  520. #else
  521. if( mIndexStream )
  522. {
  523. cmd_str = "mutt_dotlock -p -u " + QFile::encodeName(KShell::quoteArg(indexLocation()));
  524. rc = system( cmd_str.data() );
  525. }
  526. #endif
  527. break;
  528. case lock_none:
  529. default:
  530. rc = 0;
  531. break;
  532. }
  533. return rc;
  534. #endif
  535. }
  536. //-----------------------------------------------------------------------------
  537. KMFolderIndex::IndexStatus KMFolderMbox::indexStatus()
  538. {
  539. QFileInfo contInfo(location());
  540. QFileInfo indInfo(indexLocation());
  541. if (!contInfo.exists()) return KMFolderIndex::IndexOk;
  542. if (!indInfo.exists()) return KMFolderIndex::IndexMissing;
  543. // Check whether the mbox file is more than 5 seconds newer than the index
  544. // file. The 5 seconds are added to reduce the number of false alerts due
  545. // to slightly out of sync clocks of the NFS server and the local machine.
  546. return ( contInfo.lastModified() > indInfo.lastModified().addSecs(5) )
  547. ? KMFolderIndex::IndexTooOld
  548. : KMFolderIndex::IndexOk;
  549. }
  550. //-----------------------------------------------------------------------------
  551. int KMFolderMbox::createIndexFromContents()
  552. {
  553. char line[MAX_LINE];
  554. char status[8], xstatus[8];
  555. QByteArray subjStr, dateStr, fromStr, toStr, xmarkStr, *lastStr=0;
  556. QByteArray replyToIdStr, replyToAuxIdStr, referencesStr, msgIdStr;
  557. QByteArray sizeServerStr, uidStr;
  558. QByteArray contentTypeStr, charset;
  559. bool atEof = false;
  560. bool inHeader = true;
  561. KMMsgInfo* mi;
  562. QString msgStr;
  563. QRegExp regexp(MSG_SEPERATOR_REGEX);
  564. int i, num, numStatus;
  565. short needStatus;
  566. assert(mStream != 0);
  567. rewind(mStream);
  568. mMsgList.clear();
  569. num = -1;
  570. numStatus= 11;
  571. off_t offs = 0;
  572. size_t size = 0;
  573. dateStr = "";
  574. fromStr = "";
  575. toStr = "";
  576. subjStr = "";
  577. *status = '\0';
  578. *xstatus = '\0';
  579. xmarkStr = "";
  580. replyToIdStr = "";
  581. replyToAuxIdStr = "";
  582. referencesStr = "";
  583. msgIdStr = "";
  584. needStatus = 3;
  585. size_t sizeServer = 0;
  586. ulong uid = 0;
  587. while (!atEof)
  588. {
  589. off_t pos = KDE_ftell(mStream);
  590. if (!fgets(line, MAX_LINE, mStream)) atEof = true;
  591. if (atEof ||
  592. (memcmp(line, MSG_SEPERATOR_START, MSG_SEPERATOR_START_LEN)==0 &&
  593. regexp.indexIn(line) >= 0))
  594. {
  595. size = pos - offs;
  596. pos = KDE_ftell(mStream);
  597. if (num >= 0)
  598. {
  599. if (numStatus <= 0)
  600. {
  601. msgStr = i18np("Creating index file: one message done", "Creating index file: %1 messages done", num);
  602. emit statusMsg(msgStr);
  603. numStatus = 10;
  604. }
  605. if (size > 0)
  606. {
  607. msgIdStr = msgIdStr.trimmed();
  608. if( !msgIdStr.isEmpty() ) {
  609. int rightAngle;
  610. rightAngle = msgIdStr.indexOf( '>' );
  611. if( rightAngle != -1 )
  612. msgIdStr.truncate( rightAngle + 1 );
  613. }
  614. replyToIdStr = replyToIdStr.trimmed();
  615. if( !replyToIdStr.isEmpty() ) {
  616. int rightAngle;
  617. rightAngle = replyToIdStr.indexOf( '>' );
  618. if( rightAngle != -1 )
  619. replyToIdStr.truncate( rightAngle + 1 );
  620. }
  621. referencesStr = referencesStr.trimmed();
  622. if( !referencesStr.isEmpty() ) {
  623. int leftAngle, rightAngle;
  624. leftAngle = referencesStr.lastIndexOf( '<' );
  625. if( ( leftAngle != -1 )
  626. && ( replyToIdStr.isEmpty() || ( replyToIdStr[0] != '<' ) ) ) {
  627. // use the last reference, instead of missing In-Reply-To
  628. replyToIdStr = referencesStr.mid( leftAngle );
  629. }
  630. // find second last reference
  631. leftAngle = referencesStr.lastIndexOf( '<', leftAngle - 1 );
  632. if( leftAngle != -1 )
  633. referencesStr = referencesStr.mid( leftAngle );
  634. rightAngle = referencesStr.lastIndexOf( '>' );
  635. if( rightAngle != -1 )
  636. referencesStr.truncate( rightAngle + 1 );
  637. // Store the second to last reference in the replyToAuxIdStr
  638. // It is a good candidate for threading the message below if the
  639. // message In-Reply-To points to is not kept in this folder,
  640. // but e.g. in an Outbox
  641. replyToAuxIdStr = referencesStr;
  642. rightAngle = referencesStr.indexOf( '>' );
  643. if( rightAngle != -1 )
  644. replyToAuxIdStr.truncate( rightAngle + 1 );
  645. }
  646. contentTypeStr = contentTypeStr.trimmed();
  647. charset = "";
  648. if ( !contentTypeStr.isEmpty() ) {
  649. int cidx = contentTypeStr.indexOf( "charset=" );
  650. if ( cidx != -1 ) {
  651. charset = contentTypeStr.mid( cidx + 8 );
  652. if ( !charset.isEmpty() && ( charset[0] == '"' ) ) {
  653. charset = charset.mid( 1 );
  654. }
  655. cidx = 0;
  656. while ( cidx < charset.length() ) {
  657. if ( charset[cidx] == '"' ||
  658. ( !isalnum(charset[cidx]) &&
  659. charset[cidx] != '-' && charset[cidx] != '_' ) ) {
  660. break;
  661. }
  662. ++cidx;
  663. }
  664. charset.truncate( cidx );
  665. }
  666. }
  667. mi = new KMMsgInfo(folder());
  668. mi->init( subjStr.trimmed(),
  669. fromStr.trimmed(),
  670. toStr.trimmed(),
  671. 0, MessageStatus::statusNew(),
  672. xmarkStr.trimmed(),
  673. replyToIdStr, replyToAuxIdStr, msgIdStr,
  674. KMMsgEncryptionStateUnknown, KMMsgSignatureStateUnknown,
  675. KMMsgMDNStateUnknown, charset, offs, size, sizeServer, uid );
  676. mi->setStatus(status, xstatus);
  677. mi->setDate( dateStr.trimmed().constData() );
  678. mi->setDirty(false);
  679. mMsgList.append(mi, mExportsSernums );
  680. *status = '\0';
  681. *xstatus = '\0';
  682. needStatus = 3;
  683. xmarkStr = "";
  684. replyToIdStr = "";
  685. replyToAuxIdStr = "";
  686. referencesStr = "";
  687. msgIdStr = "";
  688. dateStr = "";
  689. fromStr = "";
  690. subjStr = "";
  691. sizeServer = 0;
  692. uid = 0;
  693. }
  694. else num--,numStatus++;
  695. }
  696. offs = KDE_ftell(mStream);
  697. num++;
  698. numStatus--;
  699. inHeader = true;
  700. continue;
  701. }
  702. // Is this a long header line?
  703. if (inHeader && (line[0]=='\t' || line[0]==' '))
  704. {
  705. i = 0;
  706. while (line [i]=='\t' || line [i]==' ') i++;
  707. if (line [i] < ' ' && line [i]>0) inHeader = false;
  708. else if (lastStr) *lastStr += line + i;
  709. }
  710. else lastStr = 0;
  711. if (inHeader && (line [0]=='\n' || line [0]=='\r'))
  712. inHeader = false;
  713. if (!inHeader) continue;
  714. /* -sanders Make all messages read when auto-recreating index */
  715. /* Reverted, as it breaks reading the sent mail status, for example.
  716. -till */
  717. if ( ( needStatus & 1) && strncasecmp( line, "Status:", 7 ) == 0 ) {
  718. for ( i=0; i<4 && line[i+8] > ' '; ++i ) {
  719. status[i] = line[i+8];
  720. }
  721. status[i] = '\0';
  722. needStatus &= ~1;
  723. } else if ( ( needStatus & 2 ) &&
  724. strncasecmp( line, "X-Status:", 9 ) == 0 ) {
  725. for ( i=0; i<4 && line[i+10] > ' '; ++i ) {
  726. xstatus[i] = line[i+10];
  727. }
  728. xstatus[i] = '\0';
  729. needStatus &= ~2;
  730. } else if ( strncasecmp( line, "X-KMail-Mark:", 13 ) == 0 ) {
  731. xmarkStr = QByteArray( line + 13 );
  732. } else if ( strncasecmp( line, "In-Reply-To:", 12 ) == 0 ) {
  733. replyToIdStr = QByteArray( line + 12 );
  734. lastStr = &replyToIdStr;
  735. } else if ( strncasecmp( line, "References:", 11 ) == 0 ) {
  736. referencesStr = QByteArray( line + 11 );
  737. lastStr = &referencesStr;
  738. } else if ( strncasecmp( line, "Message-Id:", 11 ) == 0 ) {
  739. msgIdStr = QByteArray( line + 11 );
  740. lastStr = &msgIdStr;
  741. } else if ( strncasecmp( line, "Date:", 5 ) == 0 ) {
  742. dateStr = QByteArray( line + 5 );
  743. lastStr = &dateStr;
  744. } else if ( strncasecmp( line, "From:", 5 ) == 0 ) {
  745. fromStr = QByteArray( line + 5 );
  746. lastStr = &fromStr;
  747. } else if ( strncasecmp( line, "To:", 3 ) == 0 ) {
  748. toStr = QByteArray( line + 3 );
  749. lastStr = &toStr;
  750. } else if ( strncasecmp( line, "Subject:", 8 ) == 0 ) {
  751. subjStr = QByteArray( line + 8 );
  752. lastStr = &subjStr;
  753. } else if ( strncasecmp( line, "X-Length:", 9 ) == 0 ) {
  754. sizeServerStr = QByteArray( line + 9 );
  755. sizeServer = sizeServerStr.toULong();
  756. lastStr = &sizeServerStr;
  757. } else if ( strncasecmp( line, "X-UID:", 6 ) == 0 ) {
  758. uidStr = QByteArray( line + 6 );
  759. uid = uidStr.toULong();
  760. lastStr = &uidStr;
  761. } else if ( strncasecmp( line, "Content-Type:", 13 ) == 0 ) {
  762. contentTypeStr = QByteArray( line + 13 );
  763. lastStr = &contentTypeStr;
  764. }
  765. }
  766. if ( mAutoCreateIndex ) {
  767. emit statusMsg( i18n("Writing index file") );
  768. writeIndex();
  769. } else {
  770. #ifdef KMAIL_SQLITE_INDEX
  771. #else
  772. mHeaderOffset = 0;
  773. #endif
  774. }
  775. correctUnreadMsgsCount();
  776. if ( kmkernel->outboxFolder() == folder() && count() > 0 ) {
  777. KMessageBox::queuedMessageBox(
  778. 0, KMessageBox::Information,
  779. i18n("Your outbox contains messages which were "
  780. "most-likely not created by KMail;\n"
  781. "please remove them from there if you "
  782. "do not want KMail to send them.") );
  783. }
  784. invalidateFolder();
  785. return 0;
  786. }
  787. //-----------------------------------------------------------------------------
  788. KMMessage* KMFolderMbox::readMsg(int idx)
  789. {
  790. KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
  791. assert(mi!=0 && !mi->isMessage());
  792. assert(mStream != 0);
  793. KMMessage *msg = new KMMessage(*mi); // note that mi is deleted by the line below
  794. mMsgList.set(idx,&msg->toMsgBase()); // done now so that the serial number can be computed
  795. msg->fromDwString(getDwString(idx));
  796. return msg;
  797. }
  798. #define STRDIM(x) (sizeof(x)/sizeof(*x)-1)
  799. // performs (\n|^)>{n}From_ -> \1>{n-1}From_ conversion
  800. static size_t unescapeFrom( char* str, size_t strLen ) {
  801. if ( !str )
  802. return 0;
  803. if ( strLen <= STRDIM(">From ") )
  804. return strLen;
  805. // yes, *d++ = *s++ is a no-op as long as d == s (until after the
  806. // first >From_), but writes are cheap compared to reads and the
  807. // data is already in the cache from the read, so special-casing
  808. // might even be slower...
  809. const char * s = str;
  810. char * d = str;
  811. const char * const e = str + strLen - STRDIM(">From ");
  812. while ( s < e ) {
  813. if ( *s == '\n' && *(s+1) == '>' ) { // we can do the lookahead, since e is 6 chars from the end!
  814. *d++ = *s++; // == '\n'
  815. *d++ = *s++; // == '>'
  816. while ( s < e && *s == '>' )
  817. *d++ = *s++;
  818. if ( qstrncmp( s, "From ", STRDIM("From ") ) == 0 )
  819. --d;
  820. }
  821. *d++ = *s++; // yes, s might be e here, but e is not the end :-)
  822. }
  823. // copy the rest:
  824. while ( s < str + strLen )
  825. *d++ = *s++;
  826. if ( d < s ) // only NUL-terminate if it's shorter
  827. *d = 0;
  828. return d - str;
  829. }
  830. //static
  831. QByteArray KMFolderMbox::escapeFrom( const DwString & str ) {
  832. const unsigned int strLen = str.length();
  833. if ( strLen <= STRDIM("From ") )
  834. return KMail::Util::ByteArray(str);
  835. // worst case: \nFrom_\nFrom_\nFrom_... => grows to 7/6
  836. QByteArray result( int( strLen + 5 ) / 6 * 7 + 1, '\0' );
  837. const char * s = str.data();
  838. const char * const e = s + strLen - STRDIM("From ");
  839. char * d = result.data();
  840. bool onlyAnglesAfterLF = false; // dont' match ^From_
  841. while ( s < e ) {
  842. switch ( *s ) {
  843. case '\n':
  844. onlyAnglesAfterLF = true;
  845. break;
  846. case '>':
  847. break;
  848. case 'F':
  849. if ( onlyAnglesAfterLF && qstrncmp( s+1, "rom ", STRDIM("rom ") ) == 0 )
  850. *d++ = '>';
  851. // fall through
  852. default:
  853. onlyAnglesAfterLF = false;
  854. break;
  855. }
  856. *d++ = *s++;
  857. }
  858. while ( s < str.data() + strLen )
  859. *d++ = *s++;
  860. result.truncate( d - result.data() );
  861. return result;
  862. }
  863. #undef STRDIM
  864. //-----------------------------------------------------------------------------
  865. DwString KMFolderMbox::getDwString(int idx)
  866. {
  867. KMMsgInfo* mi = (KMMsgInfo*)mMsgList[idx];
  868. assert(mi!=0);
  869. assert(mStream != 0);
  870. size_t msgSize = mi->msgSize();
  871. char* msgText = new char[ msgSize + 1 ];
  872. KDE_fseek(mStream, mi->folderOffset(), SEEK_SET);
  873. fread(msgText, msgSize, 1, mStream);
  874. msgText[msgSize] = '\0';
  875. size_t newMsgSize = unescapeFrom( msgText, msgSize );
  876. newMsgSize = KMail::Util::crlf2lf( msgText, newMsgSize );
  877. DwString msgStr;
  878. // the DwString takes possession of msgText, so we must not delete msgText
  879. msgStr.TakeBuffer( msgText, msgSize + 1, 0, newMsgSize );
  880. return msgStr;
  881. }
  882. //-----------------------------------------------------------------------------
  883. int KMFolderMbox::addMsg( KMMessage *aMsg, int *aIndex_ret )
  884. {
  885. if ( !canAddMsgNow( aMsg, aIndex_ret ) ) {
  886. return 0;
  887. }
  888. KMFolderOpener openThis( folder(), "mboxaddMsg" );
  889. if ( openThis.openResult() )
  890. {
  891. kDebug() << openThis.openResult() << " of folder: " << label();
  892. return openThis.openResult();
  893. }
  894. // take message out of the folder it is currently in, if any
  895. KMFolder* msgParent = aMsg->parent();
  896. int idx = -1;
  897. if ( msgParent ) {
  898. if ( msgParent== folder() ) {
  899. if ( kmkernel->folderIsDraftOrOutbox( folder() ) ) {
  900. //special case for Edit message.
  901. kDebug() << "Editing message in outbox or drafts";
  902. } else {
  903. return 0;
  904. }
  905. }
  906. idx = msgParent->find( aMsg );
  907. msgParent->getMsg( idx );
  908. }
  909. if ( folderType() != KMFolderTypeImap ) {
  910. /*
  911. QFile fileD0( "testdat_xx-kmfoldermbox-0" );
  912. if( fileD0.open( QIODevice::WriteOnly ) ) {
  913. QDataStream ds( &fileD0 );
  914. ds.writeRawData( aMsg->asString(), aMsg->asString().length() );
  915. fileD0.close(); // If data is 0 we just create a zero length file.
  916. }
  917. */
  918. aMsg->setStatusFields();
  919. /*
  920. QFile fileD1( "testdat_xx-kmfoldermbox-1" );
  921. if( fileD1.open( QIODevice::WriteOnly ) ) {
  922. QDataStream ds( &fileD1 );
  923. ds.writeRawData( aMsg->asString(), aMsg->asString().length() );
  924. fileD1.close(); // If data is 0 we just create a zero length file.
  925. }
  926. */
  927. if (aMsg->headerField("Content-Type").isEmpty()) // This might be added by
  928. aMsg->removeHeaderField("Content-Type"); // the line above
  929. }
  930. QByteArray msgText = escapeFrom( aMsg->asDwString() );
  931. size_t len = msgText.size();
  932. assert( mStream != 0 );
  933. clearerr( mStream );
  934. if ( len <= 0 ) {
  935. kDebug() << "Message added to folder `" << objectName()
  936. << "' contains no data. Ignoring it.";
  937. return 0;
  938. }
  939. // Make sure the file is large enough to check for an end
  940. // character
  941. KDE_fseek( mStream, 0, SEEK_END );
  942. off_t revert = KDE_ftell( mStream );
  943. int growth = 0;
  944. if ( KDE_ftell( mStream ) >= 2 ) {
  945. // write message to folder file
  946. char endStr[3];
  947. KDE_fseek( mStream, -2, SEEK_END );
  948. fread( endStr, 1, 2, mStream ); // ensure separating empty line
  949. if ( KDE_ftell( mStream ) > 0 && endStr[0]!='\n' ) {
  950. ++growth;
  951. KDE_fseek( mStream, 0, SEEK_END ); // required at least on Windows, Solaris, etc.
  952. if ( endStr[1]!='\n' ) {
  953. //printf ("****endStr[1]=%c\n", endStr[1]);
  954. fwrite( "\n\n", 1, 2, mStream );
  955. ++growth;
  956. } else {
  957. fwrite( "\n", 1, 1, mStream );
  958. }
  959. }
  960. }
  961. KDE_fseek( mStream, 0, SEEK_END ); // this is needed on solaris and others
  962. int error = ferror( mStream );
  963. if ( error )
  964. return error;
  965. QByteArray messageSeparator( aMsg->mboxMessageSeparator() );
  966. fwrite( messageSeparator.data(), messageSeparator.length(), 1, mStream );
  967. off_t offs = KDE_ftell( mStream );
  968. fwrite( msgText.data(), len, 1, mStream );
  969. if ( msgText[(int)len-1] != '\n' ) {
  970. fwrite( "\n\n", 1, 2, mStream );
  971. }
  972. fflush( mStream );
  973. size_t size = KDE_ftell( mStream ) - offs;
  974. error = ferror( mStream );
  975. if ( error ) {
  976. kDebug() << "Error: Could not add message to folder:" << strerror(errno);
  977. if ( KDE_ftell( mStream ) > revert ) {
  978. kDebug() << "Undoing changes";
  979. truncate( QFile::encodeName(location()), revert );
  980. }
  981. kmkernel->emergencyExit( i18n("Could not add message to folder: ") +
  982. QString::fromLocal8Bit( strerror( errno ) ) );
  983. /* This code is not 100% reliable
  984. bool busy = kmkernel->kbp()->isBusy();
  985. if (busy) kmkernel->kbp()->idle();
  986. KMessageBox::sorry(0,
  987. i18n("Unable to add message to folder.\n"
  988. "(No space left on device or insufficient quota?)\n"
  989. "Free space and sufficient quota are required to continue safely."));
  990. if (busy) kmkernel->kbp()->busy();
  991. kmkernel->kbp()->idle();
  992. */
  993. return error;
  994. }
  995. if ( msgParent ) {
  996. if ( idx >= 0 ) {
  997. msgParent->take( idx );
  998. }
  999. }
  1000. // if (mAccount) aMsg->removeHeaderField("X-UID");
  1001. if ( aMsg->status().isUnread() ||
  1002. aMsg->status().isNew() ||
  1003. (folder() == kmkernel->outboxFolder() ) ) {
  1004. if ( mUnreadMsgs == -1 ) {
  1005. mUnreadMsgs = 1;
  1006. } else {
  1007. ++mUnreadMsgs;
  1008. }
  1009. if ( !mQuiet ) {
  1010. emit numUnreadMsgsChanged( folder() );
  1011. }
  1012. }
  1013. ++mTotalMsgs;
  1014. mCachedSize = -1;
  1015. if ( aMsg->attachmentState() == KMMsgAttachmentUnknown &&
  1016. aMsg->readyToShow() )
  1017. aMsg->updateAttachmentState();
  1018. // store information about the position in the folder file in the message
  1019. aMsg->setParent( folder() );
  1020. aMsg->setFolderOffset( offs );
  1021. aMsg->setMsgSize( size );
  1022. idx = mMsgList.append( &aMsg->toMsgBase(), mExportsSernums );
  1023. if ( aMsg->getMsgSerNum() <= 0 ) {
  1024. aMsg->setMsgSerNum();
  1025. } else {
  1026. replaceMsgSerNum( aMsg->getMsgSerNum(), &aMsg->toMsgBase(), idx );
  1027. }
  1028. // change the length of the previous message to encompass white space added
  1029. if (( idx > 0) && (growth > 0) ) {
  1030. // don't grow if a deleted message claims space at the end of the file
  1031. if ( (ulong)revert == mMsgList[idx - 1]->folderOffset() + mMsgList[idx - 1]->msgSize() ) {
  1032. mMsgList[idx - 1]->setMsgSize( mMsgList[idx - 1]->msgSize() + growth );
  1033. }
  1034. }
  1035. // write index entry if desired
  1036. if ( mAutoCreateIndex ) {
  1037. #ifdef KMAIL_SQLITE_INDEX
  1038. // reset the db id, in case we have one, we are about to change folders
  1039. // and can't reuse it there
  1040. aMsg->setDbId( 0 );
  1041. #else
  1042. assert( mIndexStream != 0 );
  1043. clearerr( mIndexStream );
  1044. KDE_fseek( mIndexStream, 0, SEEK_END );
  1045. revert = KDE_ftell( mIndexStream );
  1046. #endif
  1047. KMMsgBase * mb = &aMsg->toMsgBase();
  1048. error = writeMessages( mb, true /*flush*/ );
  1049. if ( mExportsSernums ) {
  1050. error |= appendToFolderIdsFile( idx );
  1051. }
  1052. if (error) {
  1053. kWarning() <<"Error: Could not add message to folder (No space left on device?)";
  1054. #ifdef KMAIL_SQLITE_INDEX
  1055. #else
  1056. if ( KDE_ftell( mIndexStream ) > revert ) {
  1057. kWarning() <<"Undoing changes";
  1058. truncate( QFile::encodeName( indexLocation() ), revert );
  1059. }
  1060. #endif
  1061. if ( errno ) {
  1062. kmkernel->emergencyExit( i18n("Could not add message to folder: ") +
  1063. QString::fromLocal8Bit( strerror( errno ) ) );
  1064. } else {
  1065. kmkernel->emergencyExit( i18n("Could not add message to folder (No space left on device?)") );
  1066. }
  1067. /* This code may not be 100% reliable
  1068. bool busy = kmkernel->kbp()->isBusy();
  1069. if (busy) kmkernel->kbp()->idle();
  1070. KMessageBox::sorry(0,
  1071. i18n("Unable to add message to folder.\n"
  1072. "(No space left on device or insufficient quota?)\n"
  1073. "Free space and sufficient quota are required to continue safely."));
  1074. if (busy) kmkernel->kbp()->busy();
  1075. */
  1076. return error;
  1077. }
  1078. }
  1079. if ( aIndex_ret ) {
  1080. *aIndex_ret = idx;
  1081. }
  1082. emitMsgAddedSignals(idx);
  1083. // All streams have been flushed without errors if we arrive here
  1084. // Return success!
  1085. // (Don't return status of stream, it may have been closed already.)
  1086. return 0;
  1087. }
  1088. int KMFolderMbox::compact( unsigned int startIndex, int nbMessages, FILE *tmpfile,
  1089. off_t&offs, bool &done )
  1090. {
  1091. int rc = 0;
  1092. QByteArray mtext;
  1093. unsigned int stopIndex = nbMessages == -1
  1094. ? mMsgList.count()
  1095. : qMin( mMsgList.count(), startIndex + nbMessages );
  1096. //kDebug() << "KMFolderMbox: compacting from" << startIndex <<" to" << stopIndex;
  1097. for ( unsigned int idx = startIndex; idx < stopIndex; ++idx ) {
  1098. KMMsgInfo* mi = (KMMsgInfo*)mMsgList.at( idx );
  1099. size_t msize = mi->msgSize();
  1100. if ( (size_t) mtext.size() < msize + 2 ) {
  1101. mtext.resize( msize+2 );
  1102. }
  1103. off_t folder_offset = mi->folderOffset();
  1104. //now we need to find the separator! grr...
  1105. for( off_t i = folder_offset-25; true; i -= 20 ) {
  1106. off_t chunk_offset = i <= 0 ? 0 : i;
  1107. if ( KDE_fseek( mStream, chunk_offset, SEEK_SET ) == -1 ) {
  1108. rc = errno;
  1109. break;
  1110. }
  1111. if ( mtext.size() < 20 ) {
  1112. mtext.resize( 20 );
  1113. }
  1114. fread( mtext.data(), 20, 1, mStream );
  1115. if ( i <= 0 ) { //woops we've reached the top of the file, last try..
  1116. if ( mtext.indexOf( "from " ) ) {
  1117. if ( (off_t) mtext.size() < folder_offset ) {
  1118. mtext.resize( folder_offset );
  1119. }
  1120. if ( KDE_fseek( mStream, chunk_offset, SEEK_SET) == -1 ||
  1121. !fread( mtext.data(), folder_offset, 1, mStream ) ||
  1122. !fwrite( mtext.data(), folder_offset, 1, tmpfile ) ) {
  1123. rc = errno;
  1124. break;
  1125. }
  1126. offs += folder_offset;
  1127. } else {
  1128. rc = 666; // yes.. this is evil
  1129. }
  1130. break;
  1131. } else {
  1132. int last_crlf = -1;
  1133. for ( int i2 = 0; i2 < 20; i2++ ) {
  1134. if ( *(mtext.data()+i2) == '\n' ) {
  1135. last_crlf = i2;
  1136. }
  1137. }
  1138. if ( last_crlf != -1 ) {
  1139. int size = folder_offset - ( i + last_crlf + 1 );
  1140. if ( (int)mtext.size() < size ) {
  1141. mtext.resize( size );
  1142. }
  1143. if ( KDE_fseek( mStream, i + last_crlf+1, SEEK_SET ) == -1 ||
  1144. !fread( mtext.data(), size, 1, mStream ) ||
  1145. !fwrite( mtext.data(), size, 1, tmpfile ) ) {
  1146. rc = errno;
  1147. break;
  1148. }
  1149. offs += size;
  1150. break;
  1151. }
  1152. }
  1153. }
  1154. if ( rc ) {
  1155. break;
  1156. }
  1157. //now actually write the message
  1158. if ( KDE_fseek( mStream, folder_offset, SEEK_SET ) == -1 ||
  1159. !fread( mtext.data(), msize, 1, mStream ) ||
  1160. !fwrite( mtext.data(), msize, 1, tmpfile ) ) {
  1161. rc = errno;
  1162. break;
  1163. }
  1164. mi->setFolderOffset( offs );
  1165. offs += msize;
  1166. }
  1167. done = ( !rc && stopIndex == mMsgList.count() ); // finished without errors
  1168. emit compacted();
  1169. return rc;
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. int KMFolderMbox::compact( bool silent )
  1173. {
  1174. // This is called only when the user explicitly requests compaction,
  1175. // so we don't check needsCompact.
  1176. KMail::MboxCompactionJob *job =
  1177. new KMail::MboxCompactionJob( folder(), true /*immediate*/ );
  1178. int rc = job->executeNow( silent );
  1179. // Note that job autodeletes itself.
  1180. // If this is the current folder, the changed signal will ultimately call
  1181. // KMHeaders::setFolderInfoStatus which will override the message,
  1182. // so save/restore it
  1183. QString statusMsg = BroadcastStatus::instance()->statusMsg();
  1184. emit changed();
  1185. emit compacted();
  1186. BroadcastStatus::instance()->setStatusMsg( statusMsg );
  1187. return rc;
  1188. }
  1189. //-----------------------------------------------------------------------------
  1190. void KMFolderMbox::setLockType( LockType ltype )
  1191. {
  1192. mLockType = ltype;
  1193. }
  1194. //-----------------------------------------------------------------------------
  1195. void KMFolderMbox::setProcmailLockFileName( const QString &fname )
  1196. {
  1197. mProcmailLockFileName = fname;
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. int KMFolderMbox::removeContents()
  1201. {
  1202. int rc = 0;
  1203. rc = unlink(QFile::encodeName(location()));
  1204. return rc;
  1205. }
  1206. //-----------------------------------------------------------------------------
  1207. int KMFolderMbox::expungeContents()
  1208. {
  1209. int rc = 0;
  1210. if (truncate(QFile::encodeName(location()), 0))
  1211. rc = errno;
  1212. return rc;
  1213. }
  1214. //-----------------------------------------------------------------------------
  1215. /*virtual*/
  1216. qint64 KMFolderMbox::doFolderSize() const
  1217. {
  1218. QFileInfo info( location() );
  1219. return info.size();
  1220. }
  1221. //-----------------------------------------------------------------------------
  1222. #include "kmfoldermbox.moc"