2 KNode, the KDE newsreader
3 Copyright (c) 1999-2006 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
17 #include "articlewidget.h"
18 #include "knarticlefactory.h"
19 #include "knarticlemanager.h"
20 #include "knarticlewindow.h"
21 #include "kncollectionviewitem.h"
22 #include "knfoldermanager.h"
23 #include "knglobals.h"
24 #include "knhdrviewitem.h"
25 #include "knmainwidget.h"
26 #include "utilities.h"
27 #include "utils/scoped_cursor_override.h"
31 #include <kstandarddirs.h>
35 using namespace KNode
;
36 using namespace KNode::Utilities
;
40 : KNArticleCollection( KNArticleCollection::Ptr() ),
41 i_d(-1), p_arentId(-1), i_ndexDirty(false), w_asOpen(true)
46 KNFolder::KNFolder( int id
, const QString
&name
, KNFolder::Ptr parent
)
47 : KNArticleCollection(parent
), i_d(id
), i_ndexDirty(false), w_asOpen(true)
49 QString fname
=path()+QString("custom_%1").arg(i_d
);
52 m_boxFile
.setFileName(fname
+".mbox");
53 i_ndexFile
.setFileName(fname
+".idx");
54 i_nfoPath
=fname
+".info";
56 p_arentId
=parent
?parent
->id():-1;
58 if(i_ndexFile
.exists())
59 c_ount
=i_ndexFile
.size()/sizeof(DynData
);
65 KNFolder::KNFolder( int id
, const QString
&name
, const QString
&prefix
, KNFolder::Ptr parent
)
66 : KNArticleCollection(parent
), i_d(id
), i_ndexDirty(false), w_asOpen(true)
68 QString fname
=path()+QString("%1_%2").arg(prefix
).arg(i_d
);
71 m_boxFile
.setFileName(fname
+".mbox");
72 i_ndexFile
.setFileName(fname
+".idx");
73 i_nfoPath
=fname
+".info";
75 p_arentId
=parent
?parent
->id():-1;
77 if(i_ndexFile
.exists())
78 c_ount
=i_ndexFile
.size()/sizeof(DynData
);
90 void KNFolder::updateListItem()
93 l_istItem
->setLabelText( n_ame
);
95 l_istItem
->setTotalCount( c_ount
);
100 QString
KNFolder::path()
102 QString
dir( KStandardDirs::locateLocal( "data", "knode/folders/" ) );
104 KNHelper::displayInternalFileError();*/
109 bool KNFolder::readInfo(const QString
&infoPath
)
111 if(infoPath
.isEmpty())
116 KConfig
info(i_nfoPath
, KConfig::SimpleConfig
);
117 KConfigGroup
grp(&info
, QString());
118 if (!isRootFolder() && !isStandardFolder()) {
119 n_ame
=grp
.readEntry("name");
120 i_d
=grp
.readEntry("id", -1);
121 p_arentId
=grp
.readEntry("parentId", -1);
123 w_asOpen
=grp
.readEntry("wasOpen", true);
126 QFileInfo
fi(infoPath
);
127 QString fname
= fi
.absolutePath() + '/' + fi
.baseName();
131 m_boxFile
.setFileName(fname
+".mbox");
132 i_ndexFile
.setFileName(fname
+".idx");
133 c_ount
=i_ndexFile
.exists() ? (i_ndexFile
.size()/sizeof(DynData
)) : 0;
140 bool KNFolder::readInfo()
142 return readInfo(i_nfoPath
);
146 void KNFolder::writeConfig()
148 if(!i_nfoPath
.isEmpty()) {
149 KConfig
info(i_nfoPath
, KConfig::SimpleConfig
);
150 KConfigGroup
grp(&info
, QString());
151 if (!isRootFolder() && !isStandardFolder()) {
152 grp
.writeEntry("name", n_ame
);
153 grp
.writeEntry("id", i_d
);
154 grp
.writeEntry("parentId", p_arentId
);
157 grp
.writeEntry("wasOpen", l_istItem
->isExpanded());
162 void KNFolder::setParent( KNCollection::Ptr p
)
165 p_arentId
= p
? ( boost::static_pointer_cast
<KNFolder
>( p
) )->id() : -1;
169 bool KNFolder::loadHdrs()
172 kDebug(5003) <<"KNFolder::loadHdrs() : already loaded";
176 if(!i_ndexFile
.open(QIODevice::ReadOnly
)) {
177 kError(5003) <<"KNFolder::loadHdrs() : cannot open index-file!";
182 if(!m_boxFile
.open(QIODevice::ReadOnly
)) {
183 kError(5003) <<"KNFolder::loadHdrs() : cannot open mbox-file!";
189 KNLocalArticle::Ptr art
;
191 int pos1
=0, pos2
=0, cnt
=0, byteCount
;
193 ScopedCursorOverride
cursor( Qt::WaitCursor
);
194 knGlobals
.setStatusMsg(i18n(" Loading folder..."));
195 knGlobals
.top
->secureProcessEvents();
197 while(!i_ndexFile
.atEnd()) {
200 byteCount
=i_ndexFile
.read((char*)(&dynamic
), sizeof(DynData
));
201 if(byteCount
!=sizeof(DynData
)) {
202 if( i_ndexFile
.error() == QFile::NoError
) {
203 kWarning(5003) <<"KNFolder::loadHeaders() : found broken entry in index-file: Ignored!";
207 kError(5003) <<"KNFolder::loadHeaders() : corrupted index-file, IO-error!";
214 art
= KNLocalArticle::Ptr( new KNLocalArticle( thisFolderPtr() ) );
217 dynamic
.getData(art
);
220 if ( !m_boxFile
.seek( art
->startOffset() ) ) {
221 kError(5003) <<"KNFolder::loadHdrs() : cannot set mbox file-pointer!";
226 tmp
= m_boxFile
.readLine();
227 if ( tmp
.endsWith( '\n' ) )
228 tmp
.resize( tmp
.length() - 1 );
230 if( m_boxFile
.error() == QFile::NoError
) {
231 kWarning(5003) <<"found broken entry in mbox-file: Ignored!";
235 kError(5003) <<"KNFolder::loadHdrs() : corrupted mbox-file, IO-error!";
244 pos1
= tmp
.indexOf( ' ' ) + 1;
245 pos2
= tmp
.indexOf( '\t', pos1
);
250 art
->subject()->from7BitString(tmp
.mid(pos1
, pos2
-pos1
));
254 pos2
= tmp
.indexOf( '\t', pos1
);
259 art
->newsgroups()->from7BitString(tmp
.mid(pos1
, pos2
-pos1
));
264 pos2
= tmp
.indexOf( '\t', pos1
);
269 art
->to()->from7BitString(tmp
.mid(pos1
,pos2
-pos1
));
275 art
->lines()->from7BitString(tmp
.mid(pos1
,pos2
-pos1
));
287 knGlobals
.setStatusMsg( QString() );
293 bool KNFolder::unloadHdrs(bool force
)
295 if ( lockedArticles() > 0 ) {
299 if (!force
&& isNotUnloadable())
302 KNLocalArticle::Ptr a
;
303 for(int idx
=0; idx
<length(); idx
++) {
305 if (a
->hasContent() && !knGlobals
.articleManager()->unloadArticle(a
, force
))
314 bool KNFolder::loadArticle( KNLocalArticle::Ptr a
)
320 if(!m_boxFile
.open(QIODevice::ReadOnly
)) {
321 kError(5003) <<"KNFolder::loadArticle(KNLocalArticle *a) : cannot open mbox file:"
322 << m_boxFile
.fileName();
327 if ( !m_boxFile
.seek( a
->startOffset() ) ) {
328 kError(5003) <<"KNFolder::loadArticle(KNLocalArticle *a) : cannot set mbox file-pointer!";
334 m_boxFile
.readLine(); //skip X-KNode-Overview
336 unsigned int size
= a
->endOffset() - m_boxFile
.pos() - 1;
338 buff
.resize( size
+ 10 );
339 int readBytes
=m_boxFile
.read(buff
.data(), size
);
341 if ( readBytes
< (int)(size
) && m_boxFile
.error() != QFile::NoError
) { // cannot read file
342 kError(5003) <<"KNFolder::loadArticle(KNLocalArticle *a) : corrupted mbox file, IO-error!";
347 buff
.resize( readBytes
);
355 bool KNFolder::saveArticles( KNLocalArticle::List
&l
)
357 if(!isLoaded()) // loading should not be done here - keep the StorageManager in sync !!
360 if(!m_boxFile
.open(QIODevice::WriteOnly
| QIODevice::Append
)) {
361 kError(5003) <<"KNFolder::saveArticles() : cannot open mbox-file!";
369 QTextStream
ts(&m_boxFile
);
370 ts
.setCodec( "ISO 8859-1" );
372 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
375 if ( (*it
)->id() == -1 || (*it
)->collection().get() != this ) {
376 if ( (*it
)->id() != -1 ) {
377 KNFolder::Ptr oldFolder
= boost::static_pointer_cast
<KNFolder
>( (*it
)->collection() );
378 if ( !(*it
)->hasContent() )
379 if( !( clear
= oldFolder
->loadArticle( (*it
) ) ) ) {
384 KNLocalArticle::List l
;
386 oldFolder
->removeArticles( l
, false );
389 (*it
)->setCollection( thisFolderPtr() );
393 if ( byId( (*it
)->id() ) == (*it
) ) {
396 ts
<< "From aaa@aaa Mon Jan 01 00:00:00 1997\n";
398 (*it
)->setStartOffset( m_boxFile
.pos() ); //save offset
400 //write overview information
401 ts
<< "X-KNode-Overview: ";
402 ts
<< (*it
)->subject()->as7BitString(false) << '\t';
404 KMime::Headers::Base
* h
;
405 if( ( h
= (*it
)->newsgroups( false ) ) !=0 )
406 ts
<< h
->as7BitString(false);
409 if( (h
= (*it
)->to( false ) ) != 0 )
410 ts
<< h
->as7BitString(false);
413 ts
<< (*it
)->lines()->as7BitString(false) << '\n';
416 (*it
)->toStream( ts
);
420 (*it
)->setEndOffset( m_boxFile
.pos() ); //save offset
423 ArticleWidget::articleChanged( (*it
) );
428 kError(5003) <<"KNFolder::saveArticle() : article not in folder!";
433 (*it
)->KNLocalArticle::Content::clear();
442 knGlobals
.articleManager()->updateViewForCollection( thisFolderPtr() );
449 void KNFolder::removeArticles( KNLocalArticle::List
&l
, bool del
)
451 if( !isLoaded() || l
.isEmpty() )
455 for ( int idx
= 0; idx
< l
.count(); ++idx
) {
456 KNLocalArticle::Ptr a
= l
[ idx
];
457 if ( a
->isLocked() ) {
461 // check if this article belongs to this folder
468 KNGlobals::self()->articleFactory()->deleteComposerForArticle(a
);
469 ArticleWindow::closeAllWindowsForArticle( a
);
470 ArticleWidget::articleRemoved( a
);
471 delete a
->listItem();
489 void KNFolder::deleteAll()
491 if ( lockedArticles() > 0 ) {
495 if (!unloadHdrs(true))
505 void KNFolder::deleteFiles()
509 QFile::remove(i_nfoPath
);
513 void KNFolder::syncIndex(bool force
)
515 if(!i_ndexDirty
&& !force
)
518 if(!i_ndexFile
.open(QIODevice::WriteOnly
)) {
519 kError(5003) <<"KNFolder::syncIndex(bool force) : cannot open index-file!";
524 KNLocalArticle::Ptr a
;
526 for(int idx
=0; idx
<length(); idx
++) {
529 i_ndexFile
.write((char*)(&d
), sizeof(DynData
));
537 void KNFolder::closeFiles()
539 if(m_boxFile
.isOpen())
541 if(i_ndexFile
.isOpen())
546 //==============================================================================
549 void KNFolder::DynData::setData( KNLocalArticle::Ptr a
)
555 ti
=a
->date()->dateTime().toTime_t();
557 flags
[0]=a
->doMail();
558 flags
[1]=a
->mailed();
559 flags
[2]=a
->doPost();
560 flags
[3]=a
->posted();
561 flags
[4]=a
->canceled();
562 flags
[5]=a
->editDisabled();
566 void KNFolder::DynData::getData( KNLocalArticle::Ptr a
)
571 a
->date()->setDateTime( dt
);
572 a
->setStartOffset(so
);
575 a
->setDoMail(flags
[0]);
576 a
->setMailed(flags
[1]);
577 a
->setDoPost(flags
[2]);
578 a
->setPosted(flags
[3]);
579 a
->setCanceled(flags
[4]);
580 a
->setEditDisabled(flags
[5]);
584 KNFolder::Ptr
KNFolder::thisFolderPtr()
586 return KNGlobals::self()->folderManager()->folder( id() );