~ubuntu-branches/ubuntu/oneiric/kdepim/oneiric-updates

« back to all changes in this revision

Viewing changes to kmail/compactionjob.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2011-06-28 19:33:24 UTC
  • mfrom: (0.2.13) (0.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20110628193324-8yvjs8sdv9rdoo6c
Tags: 4:4.7.0-0ubuntu1
* New upstream release
  - update install files
  - add missing kdepim-doc package to control file
  - Fix Vcs lines
  - kontact breaks/replaces korganizer << 4:4.6.80
  - tighten the dependency of kdepim-dev on libkdepim4 to fix lintian error

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * Copyright (c) 2004 David Faure <faure@kde.org>
3
 
 *
4
 
 *  This program is free software; you can redistribute it and/or modify
5
 
 *  it under the terms of the GNU General Public License as published by
6
 
 *  the Free Software Foundation; version 2 of the License
7
 
 *
8
 
 *  This program is distributed in the hope that it will be useful,
9
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
 *  GNU General Public License for more details.
12
 
 *
13
 
 *  You should have received a copy of the GNU General Public License
14
 
 *  along with this program; if not, write to the Free Software
15
 
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
 
 *
17
 
 *  In addition, as a special exception, the copyright holders give
18
 
 *  permission to link the code of this program with any edition of
19
 
 *  the Qt library by Trolltech AS, Norway (or with modified versions
20
 
 *  of Qt that use the same license as Qt), and distribute linked
21
 
 *  combinations including the two.  You must obey the GNU General
22
 
 *  Public License in all respects for all of the code used other than
23
 
 *  Qt.  If you modify this file, you may extend this exception to
24
 
 *  your version of the file, but you are not obligated to do so.  If
25
 
 *  you do not wish to do so, delete this exception statement from
26
 
 *  your version.
27
 
 */
28
 
 
29
 
#include "compactionjob.h"
30
 
#include "kmfolder.h"
31
 
#include "broadcaststatus.h"
32
 
using KPIM::BroadcastStatus;
33
 
#include "kmfoldermbox.h"
34
 
#include "kmfoldermaildir.h"
35
 
 
36
 
#include <kdebug.h>
37
 
#include <kde_file.h>
38
 
#include <klocale.h>
39
 
 
40
 
#include <QFile>
41
 
#include <QFileInfo>
42
 
#include <QDir>
43
 
 
44
 
#include <sys/types.h>
45
 
#include <sys/stat.h>
46
 
#include <unistd.h>
47
 
#include <errno.h>
48
 
 
49
 
using namespace KMail;
50
 
 
51
 
// Look at this number of messages in each slotDoWork call
52
 
#define COMPACTIONJOB_NRMESSAGES 100
53
 
// And wait this number of milliseconds before calling it again
54
 
#define COMPACTIONJOB_TIMERINTERVAL 100
55
 
 
56
 
MboxCompactionJob::MboxCompactionJob( KMFolder* folder, bool immediate )
57
 
 : ScheduledJob( folder, immediate ), mTimer( this ), mTmpFile( 0 ),
58
 
   mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
59
 
{
60
 
}
61
 
 
62
 
MboxCompactionJob::~MboxCompactionJob()
63
 
{
64
 
}
65
 
 
66
 
void MboxCompactionJob::kill()
67
 
{
68
 
  Q_ASSERT( mCancellable );
69
 
  // We must close the folder if we opened it and got interrupted
70
 
  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) {
71
 
    mSrcFolder->storage()->close( "mboxcompact" );
72
 
  }
73
 
 
74
 
  if ( mTmpFile ) {
75
 
    fclose( mTmpFile );
76
 
  }
77
 
  mTmpFile = 0;
78
 
  if ( !mTempName.isEmpty() ) {
79
 
    QFile::remove( mTempName );
80
 
  }
81
 
  FolderJob::kill();
82
 
}
83
 
 
84
 
QString MboxCompactionJob::realLocation() const
85
 
{
86
 
  QString location = mSrcFolder->location();
87
 
  QFileInfo inf( location );
88
 
  if (inf.isSymLink()) {
89
 
    KUrl u; u.setPath( location );
90
 
    // follow (and resolve) symlinks so that the final KDE_rename() always works
91
 
    // KUrl gives us support for absolute and relative links transparently.
92
 
    return KUrl( u, inf.readLink() ).toLocalFile();
93
 
  }
94
 
  return location;
95
 
}
96
 
 
97
 
int MboxCompactionJob::executeNow( bool silent )
98
 
{
99
 
  mSilent = silent;
100
 
  FolderStorage *storage = mSrcFolder->storage();
101
 
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( storage );
102
 
  if ( !storage->compactable() ) {
103
 
    kDebug() << storage->location() << "compaction skipped.";
104
 
    if ( !mSilent ) {
105
 
      QString str = i18n( "For safety reasons, compaction has been disabled for %1", mbox->label() );
106
 
      BroadcastStatus::instance()->setStatusMsg( str );
107
 
    }
108
 
    return 0;
109
 
  }
110
 
  kDebug() << "Compacting" << mSrcFolder->idString();
111
 
 
112
 
  if ( KMFolderIndex::IndexOk != mbox->indexStatus() ) {
113
 
    kDebug() << "Critical error:" << storage->location()
114
 
                 << "has been modified by an external application while KMail was running.";
115
 
    //      exit(1); backed out due to broken nfs
116
 
  }
117
 
 
118
 
  const QFileInfo pathInfo( realLocation() );
119
 
  // Use /dir/.mailboxname.compacted so that it's hidden, and doesn't show up after restarting kmail
120
 
  // (e.g. due to an unfortunate crash while compaction is happening)
121
 
  mTempName = pathInfo.path() + "/." + pathInfo.fileName() + ".compacted";
122
 
 
123
 
  mode_t old_umask = umask( 077 );
124
 
  mTmpFile = KDE_fopen( QFile::encodeName( mTempName ), "w" );
125
 
  umask( old_umask );
126
 
  if (!mTmpFile) {
127
 
    kWarning() <<"Couldn't start compacting" << mSrcFolder->label()
128
 
                   << ":" << strerror( errno )
129
 
                   << "while creating" << mTempName;
130
 
    return errno;
131
 
  }
132
 
  mOpeningFolder = true; // Ignore open-notifications while opening the folder
133
 
  storage->open( "mboxcompact" );
134
 
  mOpeningFolder = false;
135
 
  mFolderOpen = true;
136
 
  mOffset = 0;
137
 
  mCurrentIndex = 0;
138
 
 
139
 
  kDebug() << "MboxCompactionJob: starting to compact folder"
140
 
               << mSrcFolder->location() << "into" << mTempName;
141
 
  connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
142
 
  if ( !mImmediate ) {
143
 
    mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
144
 
  }
145
 
  slotDoWork();
146
 
  return mErrorCode;
147
 
}
148
 
 
149
 
void MboxCompactionJob::slotDoWork()
150
 
{
151
 
  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
152
 
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
153
 
  bool bDone = false;
154
 
  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
155
 
  int rc = mbox->compact( mCurrentIndex, nbMessages,
156
 
                          mTmpFile, mOffset /*in-out*/, bDone /*out*/ );
157
 
  if ( !mImmediate )
158
 
    mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
159
 
  if ( rc || bDone ) // error, or finished
160
 
    done( rc );
161
 
}
162
 
 
163
 
void MboxCompactionJob::done( int rc )
164
 
{
165
 
  mTimer.stop();
166
 
  mCancellable = false;
167
 
  KMFolderMbox *mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
168
 
  if ( !rc ) {
169
 
    rc = fflush( mTmpFile );
170
 
  }
171
 
  if ( !rc ) {
172
 
    rc = fsync( fileno( mTmpFile ) );
173
 
  }
174
 
  rc |= fclose( mTmpFile );
175
 
  QString str;
176
 
  if ( !rc ) {
177
 
    bool autoCreate = mbox->autoCreateIndex();
178
 
    QString box( realLocation() );
179
 
    rc = KDE_rename( QFile::encodeName( mTempName ), QFile::encodeName( box ) );
180
 
    if ( rc != 0 )
181
 
      return;
182
 
    mbox->writeIndex();
183
 
    mbox->writeConfig();
184
 
    mbox->setAutoCreateIndex( false );
185
 
    mbox->close( "mboxcompact", true );
186
 
    mbox->setAutoCreateIndex( autoCreate );
187
 
    mbox->setNeedsCompacting( false );            // We are clean now
188
 
    str = i18n( "Folder \"%1\" successfully compacted", mSrcFolder->label() );
189
 
    kDebug() << str;
190
 
  } else {
191
 
    mbox->close( "mboxcompact" );
192
 
    str = i18n( "Error occurred while compacting \"%1\". Compaction aborted.", mSrcFolder->label() );
193
 
    kDebug() << "Error occurred while compacting" << mbox->location();
194
 
    kDebug() << "Compaction aborted.";
195
 
    QFile::remove( mTempName );
196
 
  }
197
 
  mErrorCode = rc;
198
 
 
199
 
  if ( !mSilent )
200
 
    BroadcastStatus::instance()->setStatusMsg( str );
201
 
 
202
 
  mFolderOpen = false;
203
 
  deleteLater(); // later, because of the "return mErrorCode"
204
 
}
205
 
 
206
 
////
207
 
 
208
 
MaildirCompactionJob::MaildirCompactionJob( KMFolder* folder, bool immediate )
209
 
 : ScheduledJob( folder, immediate ), mTimer( this ),
210
 
   mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
211
 
{
212
 
}
213
 
 
214
 
MaildirCompactionJob::~MaildirCompactionJob()
215
 
{
216
 
}
217
 
 
218
 
void MaildirCompactionJob::kill()
219
 
{
220
 
  Q_ASSERT( mCancellable );
221
 
  // We must close the folder if we opened it and got interrupted
222
 
  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) {
223
 
    mSrcFolder->storage()->close( "maildircompact" );
224
 
  }
225
 
 
226
 
  FolderJob::kill();
227
 
}
228
 
 
229
 
int MaildirCompactionJob::executeNow( bool silent )
230
 
{
231
 
  mSilent = silent;
232
 
  KMFolderMaildir *storage =
233
 
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
234
 
  kDebug() << "Compacting" << mSrcFolder->idString();
235
 
 
236
 
  mOpeningFolder = true; // Ignore open-notifications while opening the folder
237
 
  storage->open( "maildircompact" );
238
 
  mOpeningFolder = false;
239
 
  mFolderOpen = true;
240
 
  QString subdirNew( storage->location() + "/new/" );
241
 
  QDir d( subdirNew );
242
 
  mEntryList = d.entryList();
243
 
  mCurrentIndex = 0;
244
 
 
245
 
  kDebug() << "MaildirCompactionJob: starting to compact in folder"
246
 
               << mSrcFolder->location();
247
 
  connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
248
 
  if ( !mImmediate ) {
249
 
    mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
250
 
  }
251
 
  slotDoWork();
252
 
  return mErrorCode;
253
 
}
254
 
 
255
 
void MaildirCompactionJob::slotDoWork()
256
 
{
257
 
  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
258
 
  KMFolderMaildir *storage =
259
 
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
260
 
  bool bDone = false;
261
 
  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
262
 
  int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone /*out*/ );
263
 
  if ( !mImmediate )
264
 
    mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
265
 
  if ( rc || bDone ) // error, or finished
266
 
    done( rc );
267
 
}
268
 
 
269
 
void MaildirCompactionJob::done( int rc )
270
 
{
271
 
  KMFolderMaildir *storage =
272
 
    static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
273
 
  mTimer.stop();
274
 
  mCancellable = false;
275
 
  QString str;
276
 
  if ( !rc ) {
277
 
    str = i18n( "Folder \"%1\" successfully compacted", mSrcFolder->label() );
278
 
  } else {
279
 
    str = i18n( "Error occurred while compacting \"%1\". Compaction aborted.", mSrcFolder->label() );
280
 
  }
281
 
  mErrorCode = rc;
282
 
  storage->setNeedsCompacting( false );
283
 
  storage->close( "maildircompact" );
284
 
  if ( storage->isOpened() ) {
285
 
    storage->updateIndex();
286
 
  }
287
 
  if ( !mSilent ) {
288
 
    BroadcastStatus::instance()->setStatusMsg( str );
289
 
  }
290
 
 
291
 
  mFolderOpen = false;
292
 
  deleteLater(); // later, because of the "return mErrorCode"
293
 
}
294
 
 
295
 
ScheduledJob *ScheduledCompactionTask::run()
296
 
{
297
 
  if ( !folder() || !folder()->needsCompacting() )
298
 
    return 0;
299
 
  switch( folder()->storage()->folderType() ) {
300
 
  case KMFolderTypeMbox:
301
 
    return new MboxCompactionJob( folder(), isImmediate() );
302
 
  case KMFolderTypeCachedImap:
303
 
  case KMFolderTypeMaildir:
304
 
    return new MaildirCompactionJob( folder(), isImmediate() );
305
 
  default: // imap, search, unknown...
306
 
    return 0;
307
 
  }
308
 
}
309
 
 
310
 
#include "compactionjob.moc"