kde-playground/kdepim/knode/knfolder.cpp
2015-04-14 21:49:29 +00:00

599 lines
13 KiB
C++

/*
KNode, the KDE newsreader
Copyright (c) 1999-2006 the KNode authors.
See file AUTHORS for details
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
*/
#include "knfolder.h"
#include "articlewidget.h"
#include "knarticlefactory.h"
#include "knarticlemanager.h"
#include "knarticlewindow.h"
#include "kncollectionviewitem.h"
#include "knfoldermanager.h"
#include "knglobals.h"
#include "knhdrviewitem.h"
#include "knmainwidget.h"
#include "utilities.h"
#include "utils/scoped_cursor_override.h"
#include <QFileInfo>
#include <kconfig.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <klocale.h>
using namespace KNode;
using namespace KNode::Utilities;
KNFolder::KNFolder()
: KNArticleCollection( KNArticleCollection::Ptr() ),
i_d(-1), p_arentId(-1), i_ndexDirty(false), w_asOpen(true)
{
}
KNFolder::KNFolder( int id, const QString &name, KNFolder::Ptr parent )
: KNArticleCollection(parent), i_d(id), i_ndexDirty(false), w_asOpen(true)
{
QString fname=path()+QString("custom_%1").arg(i_d);
n_ame = name;
m_boxFile.setFileName(fname+".mbox");
i_ndexFile.setFileName(fname+".idx");
i_nfoPath=fname+".info";
p_arentId=parent?parent->id():-1;
if(i_ndexFile.exists())
c_ount=i_ndexFile.size()/sizeof(DynData);
else
c_ount=0;
}
KNFolder::KNFolder( int id, const QString &name, const QString &prefix, KNFolder::Ptr parent )
: KNArticleCollection(parent), i_d(id), i_ndexDirty(false), w_asOpen(true)
{
QString fname=path()+QString("%1_%2").arg(prefix).arg(i_d);
n_ame = name;
m_boxFile.setFileName(fname+".mbox");
i_ndexFile.setFileName(fname+".idx");
i_nfoPath=fname+".info";
p_arentId=parent?parent->id():-1;
if(i_ndexFile.exists())
c_ount=i_ndexFile.size()/sizeof(DynData);
else
c_ount=0;
}
KNFolder::~KNFolder()
{
closeFiles();
}
void KNFolder::updateListItem()
{
if(l_istItem) {
l_istItem->setLabelText( n_ame );
if (!isRootFolder())
l_istItem->setTotalCount( c_ount );
}
}
QString KNFolder::path()
{
QString dir( KStandardDirs::locateLocal( "data", "knode/folders/" ) );
/*if (dir.isNull())
KNHelper::displayInternalFileError();*/
return dir;
}
bool KNFolder::readInfo(const QString &infoPath)
{
if(infoPath.isEmpty())
return false;
i_nfoPath=infoPath;
KConfig info(i_nfoPath, KConfig::SimpleConfig);
KConfigGroup grp(&info, QString());
if (!isRootFolder() && !isStandardFolder()) {
n_ame=grp.readEntry("name");
i_d=grp.readEntry("id", -1);
p_arentId=grp.readEntry("parentId", -1);
}
w_asOpen=grp.readEntry("wasOpen", true);
if(i_d>-1) {
QFileInfo fi(infoPath);
QString fname = fi.absolutePath() + '/' + fi.baseName();
closeFiles();
clear();
m_boxFile.setFileName(fname+".mbox");
i_ndexFile.setFileName(fname+".idx");
c_ount=i_ndexFile.exists() ? (i_ndexFile.size()/sizeof(DynData)) : 0;
}
return (i_d!=-1);
}
bool KNFolder::readInfo()
{
return readInfo(i_nfoPath);
}
void KNFolder::writeConfig()
{
if(!i_nfoPath.isEmpty()) {
KConfig info(i_nfoPath, KConfig::SimpleConfig);
KConfigGroup grp(&info, QString());
if (!isRootFolder() && !isStandardFolder()) {
grp.writeEntry("name", n_ame);
grp.writeEntry("id", i_d);
grp.writeEntry("parentId", p_arentId);
}
if(l_istItem)
grp.writeEntry("wasOpen", l_istItem->isExpanded());
}
}
void KNFolder::setParent( KNCollection::Ptr p )
{
p_arent = p;
p_arentId = p ? ( boost::static_pointer_cast<KNFolder>( p ) )->id() : -1;
}
bool KNFolder::loadHdrs()
{
if(isLoaded()) {
kDebug(5003) <<"KNFolder::loadHdrs() : already loaded";
return true;
}
if(!i_ndexFile.open(QIODevice::ReadOnly)) {
kError(5003) <<"KNFolder::loadHdrs() : cannot open index-file!";
closeFiles();
return false;
}
if(!m_boxFile.open(QIODevice::ReadOnly)) {
kError(5003) <<"KNFolder::loadHdrs() : cannot open mbox-file!";
closeFiles();
return false;
}
QByteArray tmp;
KNLocalArticle::Ptr art;
DynData dynamic;
int pos1=0, pos2=0, cnt=0, byteCount;
ScopedCursorOverride cursor( Qt::WaitCursor );
knGlobals.setStatusMsg(i18n(" Loading folder..."));
knGlobals.top->secureProcessEvents();
while(!i_ndexFile.atEnd()) {
//read index-data
byteCount=i_ndexFile.read((char*)(&dynamic), sizeof(DynData));
if(byteCount!=sizeof(DynData)) {
if( i_ndexFile.error() == QFile::NoError ) {
kWarning(5003) <<"KNFolder::loadHeaders() : found broken entry in index-file: Ignored!";
continue;
}
else {
kError(5003) <<"KNFolder::loadHeaders() : corrupted index-file, IO-error!";
closeFiles();
clear();
return false;
}
}
art = KNLocalArticle::Ptr( new KNLocalArticle( thisFolderPtr() ) );
//set index-data
dynamic.getData(art);
//read overview
if ( !m_boxFile.seek( art->startOffset() ) ) {
kError(5003) <<"KNFolder::loadHdrs() : cannot set mbox file-pointer!";
closeFiles();
clear();
return false;
}
tmp = m_boxFile.readLine();
if ( tmp.endsWith( '\n' ) )
tmp.resize( tmp.length() - 1 );
if(tmp.isEmpty()) {
if( m_boxFile.error() == QFile::NoError ) {
kWarning(5003) <<"found broken entry in mbox-file: Ignored!";
continue;
}
else {
kError(5003) <<"KNFolder::loadHdrs() : corrupted mbox-file, IO-error!";
closeFiles();
clear();
return false;
}
}
//set overview
bool end=false;
pos1 = tmp.indexOf( ' ' ) + 1;
pos2 = tmp.indexOf( '\t', pos1 );
if (pos2 == -1) {
pos2=tmp.length();
end=true;
}
art->subject()->from7BitString(tmp.mid(pos1, pos2-pos1));
if (!end) {
pos1=pos2+1;
pos2 = tmp.indexOf( '\t', pos1 );
if (pos2 == -1) {
pos2=tmp.length();
end=true;
}
art->newsgroups()->from7BitString(tmp.mid(pos1, pos2-pos1));
}
if (!end) {
pos1=pos2+1;
pos2 = tmp.indexOf( '\t', pos1 );
if (pos2 == -1) {
pos2=tmp.length();
end=true;
}
art->to()->from7BitString(tmp.mid(pos1,pos2-pos1));
}
if (!end) {
pos1=pos2+1;
pos2=tmp.length();
art->lines()->from7BitString(tmp.mid(pos1,pos2-pos1));
}
append( art );
cnt++;
}
closeFiles();
setLastID();
c_ount=cnt;
updateListItem();
knGlobals.setStatusMsg( QString() );
return true;
}
bool KNFolder::unloadHdrs(bool force)
{
if ( lockedArticles() > 0 ) {
return false;
}
if (!force && isNotUnloadable())
return false;
KNLocalArticle::Ptr a;
for(int idx=0; idx<length(); idx++) {
a=at(idx);
if (a->hasContent() && !knGlobals.articleManager()->unloadArticle(a, force))
return false;
}
syncIndex();
clear();
return true;
}
bool KNFolder::loadArticle( KNLocalArticle::Ptr a )
{
if(a->hasContent())
return true;
closeFiles();
if(!m_boxFile.open(QIODevice::ReadOnly)) {
kError(5003) <<"KNFolder::loadArticle(KNLocalArticle *a) : cannot open mbox file:"
<< m_boxFile.fileName();
return false;
}
//set file-pointer
if ( !m_boxFile.seek( a->startOffset() ) ) {
kError(5003) <<"KNFolder::loadArticle(KNLocalArticle *a) : cannot set mbox file-pointer!";
closeFiles();
return false;
}
//read content
m_boxFile.readLine(); //skip X-KNode-Overview
unsigned int size = a->endOffset() - m_boxFile.pos() - 1;
QByteArray buff;
buff.resize( size + 10 );
int readBytes=m_boxFile.read(buff.data(), size);
closeFiles();
if ( readBytes < (int)(size) && m_boxFile.error() != QFile::NoError ) { // cannot read file
kError(5003) <<"KNFolder::loadArticle(KNLocalArticle *a) : corrupted mbox file, IO-error!";
return false;
}
//set content
buff.resize( readBytes );
a->setContent(buff);
a->parse();
return true;
}
bool KNFolder::saveArticles( KNLocalArticle::List &l )
{
if(!isLoaded()) // loading should not be done here - keep the StorageManager in sync !!
return false;
if(!m_boxFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
kError(5003) <<"KNFolder::saveArticles() : cannot open mbox-file!";
closeFiles();
return false;
}
int addCnt=0;
bool ret=true;
bool clear=false;
QTextStream ts(&m_boxFile);
ts.setCodec( "ISO 8859-1" );
for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
clear=false;
if ( (*it)->id() == -1 || (*it)->collection().get() != this ) {
if ( (*it)->id() != -1 ) {
KNFolder::Ptr oldFolder = boost::static_pointer_cast<KNFolder>( (*it)->collection() );
if ( !(*it)->hasContent() )
if( !( clear = oldFolder->loadArticle( (*it) ) ) ) {
ret = false;
continue;
}
KNLocalArticle::List l;
l.append( (*it) );
oldFolder->removeArticles( l, false );
}
append( (*it) );
(*it)->setCollection( thisFolderPtr() );
addCnt++;
}
if ( byId( (*it)->id() ) == (*it) ) {
//MBox
ts << "From aaa@aaa Mon Jan 01 00:00:00 1997\n";
ts.flush();
(*it)->setStartOffset( m_boxFile.pos() ); //save offset
//write overview information
ts << "X-KNode-Overview: ";
ts << (*it)->subject()->as7BitString(false) << '\t';
KMime::Headers::Base* h;
if( ( h = (*it)->newsgroups( false ) ) !=0 )
ts << h->as7BitString(false);
ts << '\t';
if( (h = (*it)->to( false ) ) != 0 )
ts << h->as7BitString(false);
ts << '\t';
ts << (*it)->lines()->as7BitString(false) << '\n';
//write article
(*it)->toStream( ts );
ts << "\n";
ts.flush();
(*it)->setEndOffset( m_boxFile.pos() ); //save offset
//update
ArticleWidget::articleChanged( (*it) );
i_ndexDirty=true;
}
else {
kError(5003) <<"KNFolder::saveArticle() : article not in folder!";
ret=false;
}
if ( clear )
(*it)->KNLocalArticle::Content::clear();
}
closeFiles();
syncIndex();
if(addCnt>0) {
c_ount=length();
updateListItem();
knGlobals.articleManager()->updateViewForCollection( thisFolderPtr() );
}
return ret;
}
void KNFolder::removeArticles( KNLocalArticle::List &l, bool del )
{
if( !isLoaded() || l.isEmpty() )
return;
int delCnt = 0;
for ( int idx = 0; idx < l.count(); ++idx ) {
KNLocalArticle::Ptr a = l[ idx ];
if ( a->isLocked() ) {
continue;
}
// check if this article belongs to this folder
a = byId( a->id() );
if ( !a ) {
continue;
}
//update
KNGlobals::self()->articleFactory()->deleteComposerForArticle(a);
ArticleWindow::closeAllWindowsForArticle( a );
ArticleWidget::articleRemoved( a );
delete a->listItem();
//delete article
remove( a );
delCnt++;
if(!del)
a->setId(-1);
}
if(delCnt>0) {
compact();
c_ount-=delCnt;
updateListItem();
i_ndexDirty=true;
}
}
void KNFolder::deleteAll()
{
if ( lockedArticles() > 0 ) {
return;
}
if (!unloadHdrs(true))
return;
clear();
c_ount=0;
syncIndex(true);
updateListItem();
}
void KNFolder::deleteFiles()
{
m_boxFile.remove();
i_ndexFile.remove();
QFile::remove(i_nfoPath);
}
void KNFolder::syncIndex(bool force)
{
if(!i_ndexDirty && !force)
return;
if(!i_ndexFile.open(QIODevice::WriteOnly)) {
kError(5003) <<"KNFolder::syncIndex(bool force) : cannot open index-file!";
closeFiles();
return;
}
KNLocalArticle::Ptr a;
DynData d;
for(int idx=0; idx<length(); idx++) {
a=at(idx);
d.setData(a);
i_ndexFile.write((char*)(&d), sizeof(DynData));
}
closeFiles();
i_ndexDirty=false;
}
void KNFolder::closeFiles()
{
if(m_boxFile.isOpen())
m_boxFile.close();
if(i_ndexFile.isOpen())
i_ndexFile.close();
}
//==============================================================================
void KNFolder::DynData::setData( KNLocalArticle::Ptr a )
{
id=a->id();
so=a->startOffset();
eo=a->endOffset();
sId=a->serverId();
ti=a->date()->dateTime().toTime_t();
flags[0]=a->doMail();
flags[1]=a->mailed();
flags[2]=a->doPost();
flags[3]=a->posted();
flags[4]=a->canceled();
flags[5]=a->editDisabled();
}
void KNFolder::DynData::getData( KNLocalArticle::Ptr a )
{
a->setId(id);
KDateTime dt;
dt.setTime_t( ti );
a->date()->setDateTime( dt );
a->setStartOffset(so);
a->setEndOffset(eo);
a->setServerId(sId);
a->setDoMail(flags[0]);
a->setMailed(flags[1]);
a->setDoPost(flags[2]);
a->setPosted(flags[3]);
a->setCanceled(flags[4]);
a->setEditDisabled(flags[5]);
}
KNFolder::Ptr KNFolder::thisFolderPtr()
{
return KNGlobals::self()->folderManager()->folder( id() );
}