split message into several paras and fix file extension markup
[kdepim.git] / knode / kncleanup.cpp
blob9bb826bb9cb5e232ef7a2d8345dcbbd5a86e34d8
1 /*
2 KNode, the KDE newsreader
3 Copyright (c) 1999-2005 the KNode authors.
4 See file AUTHORS for details
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
16 #include <QDir>
17 #include <QFile>
18 #include <QLabel>
19 #include <QProgressBar>
20 #include <QVBoxLayout>
21 #include <QApplication>
22 #include <QFrame>
23 #include <QTextStream>
24 #include <QCloseEvent>
26 #include <klocale.h>
27 #include <kmessagebox.h>
28 #include <kseparator.h>
29 #include <kdebug.h>
31 #include "knfolder.h"
32 #include "knglobals.h"
33 #include "kncleanup.h"
34 #include "knconfig.h"
35 #include "knfoldermanager.h"
36 #include "kngroupmanager.h"
37 #include "knarticlemanager.h"
38 #include "knnntpaccount.h"
41 KNCleanUp::KNCleanUp() : d_lg(0)
46 KNCleanUp::~KNCleanUp()
48 delete d_lg;
52 void KNCleanUp::start()
54 if ( mColList.isEmpty() )
55 return;
57 d_lg = new ProgressDialog( mColList.count() );
58 d_lg->show();
60 for ( KNArticleCollection::List::Iterator it = mColList.begin(); it != mColList.end(); ++it ) {
61 if ( (*it)->type() == KNCollection::CTgroup ) {
62 d_lg->showMessage( i18n( "Deleting expired articles in <b>%1</b>", (*it)->name() ) ); // krazy:exclude=qmethods
63 qApp->processEvents();
64 expireGroup( boost::static_pointer_cast<KNGroup>( (*it) ) );
65 d_lg->doProgress();
67 else if ( (*it)->type() == KNCollection::CTfolder ) {
68 d_lg->showMessage( i18n("Compacting folder <b>%1</b>", (*it)->name() ) ); // krazy:exclude=qmethods
69 qApp->processEvents();
70 compactFolder( boost::static_pointer_cast<KNFolder>( (*it) ) );
71 d_lg->doProgress();
75 delete d_lg;
76 d_lg=0;
80 void KNCleanUp::reset()
82 mColList.clear();
83 delete d_lg;
84 d_lg=0;
88 void KNCleanUp::expireGroup( KNGroup::Ptr g, bool showResult )
90 int expDays=0, idRef=0, foundId=-1, delCnt=0, leftCnt=0, newCnt=0, firstArtNr=g->firstNr(), firstNew=-1;
91 bool unavailable=false;
92 KNRemoteArticle::Ptr art, ref;
94 KNode::Cleanup *conf = g->activeCleanupConfig();
96 g->setNotUnloadable(true);
98 if (!g->isLoaded() && !knGlobals.groupManager()->loadHeaders(g)) {
99 g->setNotUnloadable(false);
100 return;
103 //find all expired
104 for(int i=0; i<g->length(); ++i) {
105 art=g->at(i);
106 if(art->isRead())
107 expDays = conf->maxAgeForRead();
108 else
109 expDays = conf->maxAgeForUnread();
111 unavailable = false;
112 if ((art->articleNumber() != -1) && conf->removeUnavailable())
113 unavailable = (art->articleNumber() < firstArtNr);
115 art->setExpired( (art->date()->ageInDays() >= expDays) || unavailable );
118 //save threads
119 if (conf->preserveThreads()) {
120 for(int i=0; i<g->length(); ++i) {
121 art=g->at(i);
122 if(!art->isExpired()) {
123 idRef=art->idRef();
124 while(idRef!=0) {
125 ref=g->byId(idRef);
126 ref->setExpired(false);
127 idRef=ref->idRef();
133 //restore threading
134 for(int i=0; i<g->length(); ++i) {
135 art=g->at(i);
136 if(!art->isExpired()) {
137 idRef=art->idRef();
138 foundId=0;
139 while(foundId==0 && idRef!=0) {
140 ref=g->byId(idRef);
141 if(!ref->isExpired()) foundId=ref->id();
142 idRef=ref->idRef();
144 art->setIdRef(foundId);
148 //delete expired
149 for(int i=0; i<g->length(); ++i) {
150 art=g->at(i);
151 if(art->isExpired()) {
152 if(art->isRead())
153 g->decReadCount();
154 delCnt++;
155 if (art->hasContent())
156 knGlobals.articleManager()->unloadArticle(art, true);
158 else if(art->isNew() && !art->isRead()) {
159 if(firstNew==-1)
160 firstNew=i;
161 newCnt++;
165 g->setNotUnloadable(false);
167 if(delCnt>0) {
168 g->saveStaticData(g->length(), true);
169 g->saveDynamicData(g->length(), true);
170 g->decCount(delCnt);
171 g->setNewCount(newCnt);
172 g->setFirstNewIndex(firstNew);
173 g->writeConfig();
174 knGlobals.groupManager()->unloadHeaders(g, true);
176 else
177 g->syncDynamicData();
179 conf->setLastExpireDate();
180 g->writeConfig();
181 leftCnt=g->count();
183 kDebug(5003) <<"KNCleanUp::expireGroup() :" << g->groupname() <<":"
184 << delCnt << "deleted ," << leftCnt << "left";
186 if(showResult)
187 KMessageBox::information(knGlobals.topWidget,
188 i18n("<b>%1</b><br />expired: %2<br />left: %3", g->groupname(), delCnt, leftCnt));
192 void KNCleanUp::compactFolder( KNFolder::Ptr f )
194 KNLocalArticle::Ptr art;
196 if (!f)
197 return;
199 QDir dir(f->path());
201 if(!dir.exists())
202 return;
204 f->setNotUnloadable(true);
206 if (!f->isLoaded() && !knGlobals.folderManager()->loadHeaders(f)) {
207 f->setNotUnloadable(false);
208 return;
211 f->closeFiles();
212 QFileInfo info(f->m_boxFile);
213 QString oldName=info.fileName();
214 QString newName=oldName+".new";
215 QFile newMBoxFile( info.absolutePath() + '/' + newName );
217 if( (f->m_boxFile.open(QIODevice::ReadOnly)) && (newMBoxFile.open(QIODevice::WriteOnly)) ) {
218 QTextStream ts(&newMBoxFile);
219 ts.setCodec( "ISO 8859-1" );
220 for(int idx=0; idx<f->length(); idx++) {
221 art=f->at(idx);
222 if ( f->m_boxFile.seek( art->startOffset() ) ) {
223 ts << "From aaa@aaa Mon Jan 01 00:00:00 1997\n";
224 ts.flush();
225 art->setStartOffset( newMBoxFile.pos() );
226 while ( f->m_boxFile.pos() < (uint)art->endOffset() && !f->m_boxFile.atEnd() )
227 ts << f->m_boxFile.readLine();
228 ts.flush();
229 art->setEndOffset( newMBoxFile.pos() );
230 newMBoxFile.putChar('\n');
234 f->syncIndex(true);
235 newMBoxFile.close();
236 f->closeFiles();
238 dir.remove(oldName);
239 dir.rename(newName, oldName);
242 f->setNotUnloadable(false);
246 //===============================================================================================
249 KNCleanUp::ProgressDialog::ProgressDialog( int steps, QWidget *parent ) :
250 KDialog( parent )
252 const int w=400,
253 h=160;
255 setCaption(i18n("Cleaning Up"));
256 setButtons( KDialog::None );
258 setFixedSize(w,h);
259 QFrame *top = new QFrame( this );
260 top->setGeometry(0,0, w,h);
262 QVBoxLayout *topL=new QVBoxLayout(top);
263 topL->setSpacing(10);
265 QLabel *l=new QLabel(i18n("Cleaning up. Please wait..."),top);
266 topL->addWidget(l);
268 KSeparator *sep=new KSeparator(top);
269 topL->addWidget(sep);
271 m_sg=new QLabel(top);
272 topL->addWidget(m_sg);
274 mProgressBar = new QProgressBar( top );
275 topL->addWidget( mProgressBar );
276 mProgressBar->setRange( 0, steps );
277 mProgressBar->setValue( 0 );
280 if(knGlobals.topWidget->isVisible()) {
281 int x, y;
282 x=(knGlobals.topWidget->width()-w)/2;
283 y=(knGlobals.topWidget->height()-h)/2;
284 if(x<0 || y<0) {
285 x=0;
286 y=0;
288 x+=knGlobals.topWidget->x();
289 y+=knGlobals.topWidget->y();
290 move(x,y);
295 KNCleanUp::ProgressDialog::~ProgressDialog()
300 void KNCleanUp::ProgressDialog::showMessage(const QString &s)
302 m_sg->setText(s);
306 void KNCleanUp::ProgressDialog::doProgress()
308 mProgressBar->setValue( mProgressBar->value() + 1 );
312 void KNCleanUp::ProgressDialog::closeEvent(QCloseEvent *)
314 // do nothing => prevent that the user closes the window