diff options
Diffstat (limited to 'knode/knfolder.cpp')
-rw-r--r-- | knode/knfolder.cpp | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/knode/knfolder.cpp b/knode/knfolder.cpp new file mode 100644 index 000000000..9cdb2f054 --- /dev/null +++ b/knode/knfolder.cpp @@ -0,0 +1,601 @@ +/* + KNode, the KDE newsreader + Copyright (c) 1999-2005 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 <qfileinfo.h> + +#include <ksimpleconfig.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <klocale.h> + +#include <kqcstringsplitter.h> + +#include "articlewidget.h" +#include "knarticlemanager.h" +#include "kncollectionviewitem.h" +#include "knhdrviewitem.h" +#include "utilities.h" +#include "knglobals.h" +#include "knarticlefactory.h" +#include "knfolder.h" +#include "knarticlewindow.h" +#include "knmainwidget.h" + +using namespace KNode; + + +KNFolder::KNFolder() + : KNArticleCollection(0), i_d(-1), p_arentId(-1), i_ndexDirty(false), w_asOpen(true) +{ +} + + +KNFolder::KNFolder(int id, const QString &name, KNFolder *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.setName(fname+".mbox"); + i_ndexFile.setName(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 *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.setName(fname+".mbox"); + i_ndexFile.setName(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->setText(0, n_ame); + if (!isRootFolder()) + l_istItem->setTotalCount( c_ount ); + } +} + + +QString KNFolder::path() +{ + QString dir(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; + + KSimpleConfig info(i_nfoPath); + if (!isRootFolder() && !isStandardFolder()) { + n_ame=info.readEntry("name"); + i_d=info.readNumEntry("id", -1); + p_arentId=info.readNumEntry("parentId", -1); + } + w_asOpen=info.readBoolEntry("wasOpen", true); + + if(i_d>-1) { + QFileInfo fi(infoPath); + QString fname=fi.dirPath(true)+"/"+fi.baseName(); + closeFiles(); + clear(); + + m_boxFile.setName(fname+".mbox"); + i_ndexFile.setName(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::saveInfo() +{ + if(!i_nfoPath.isEmpty()) { + KSimpleConfig info(i_nfoPath); + if (!isRootFolder() && !isStandardFolder()) { + info.writeEntry("name", n_ame); + info.writeEntry("id", i_d); + info.writeEntry("parentId", p_arentId); + } + if(l_istItem) + info.writeEntry("wasOpen", l_istItem->isOpen()); + } +} + + +void KNFolder::setParent(KNCollection *p) +{ + p_arent = p; + p_arentId = p ? (static_cast<KNFolder*>(p))->id() : -1; +} + + +bool KNFolder::loadHdrs() +{ + if(isLoaded()) { + kdDebug(5003) << "KNFolder::loadHdrs() : already loaded" << endl; + return true; + } + + if(!i_ndexFile.open(IO_ReadOnly)) { + kdError(5003) << "KNFolder::loadHdrs() : cannot open index-file!" << endl; + closeFiles(); + return false; + } + + if(!m_boxFile.open(IO_ReadOnly)) { + kdError(5003) << "KNFolder::loadHdrs() : cannot open mbox-file!" << endl; + closeFiles(); + return false; + } + + if(!resize(c_ount)) { + closeFiles(); + return false; + } + + QCString tmp; + KQCStringSplitter split; + KNLocalArticle *art; + DynData dynamic; + int pos1=0, pos2=0, cnt=0, byteCount; + + knGlobals.top->setCursorBusy(true); + knGlobals.setStatusMsg(i18n(" Loading folder...")); + knGlobals.top->secureProcessEvents(); + + while(!i_ndexFile.atEnd()) { + + //read index-data + byteCount=i_ndexFile.readBlock((char*)(&dynamic), sizeof(DynData)); + if(byteCount!=sizeof(DynData)) + if(i_ndexFile.status() == IO_Ok) { + kdWarning(5003) << "KNFolder::loadHeaders() : found broken entry in index-file: Ignored!" << endl; + continue; + } + else { + kdError(5003) << "KNFolder::loadHeaders() : corrupted index-file, IO-error!" << endl; + closeFiles(); + clear(); + knGlobals.top->setCursorBusy( false ); + return false; + } + + art=new KNLocalArticle(this); + + //set index-data + dynamic.getData(art); + + //read overview + if(!m_boxFile.at(art->startOffset())) { + kdError(5003) << "KNFolder::loadHdrs() : cannot set mbox file-pointer!" << endl; + closeFiles(); + clear(); + knGlobals.top->setCursorBusy( false ); + return false; + } + tmp=m_boxFile.readLine(); //KNFile::readLine() + if(tmp.isEmpty()) { + if(m_boxFile.status() == IO_Ok) { + kdWarning(5003) << "found broken entry in mbox-file: Ignored!" << endl; + delete art; + continue; + } + else { + kdError(5003) << "KNFolder::loadHdrs() : corrupted mbox-file, IO-error!"<< endl; + closeFiles(); + clear(); + knGlobals.top->setCursorBusy( false ); + return false; + } + } + + //set overview + bool end=false; + pos1=tmp.find(' ')+1; + pos2=tmp.find('\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.find('\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.find('\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)); + } + + if(!append(art)) { + kdError(5003) << "KNFolder::loadHdrs() : cannot append article!"<< endl; + delete art; + clear(); + closeFiles(); + + knGlobals.setStatusMsg(QString::null); + knGlobals.top->setCursorBusy(false); + return false; + } + + cnt++; + } + + closeFiles(); + setLastID(); + c_ount=cnt; + updateListItem(); + + knGlobals.setStatusMsg(QString::null); + knGlobals.top->setCursorBusy(false); + + return true; +} + + +bool KNFolder::unloadHdrs(bool force) +{ + if(l_ockedArticles>0) + return false; + + if (!force && isNotUnloadable()) + return false; + + KNLocalArticle *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 *a) +{ + if(a->hasContent()) + return true; + + closeFiles(); + if(!m_boxFile.open(IO_ReadOnly)) { + kdError(5003) << "KNFolder::loadArticle(KNLocalArticle *a) : cannot open mbox file: " + << m_boxFile.name() << endl; + return false; + } + + //set file-pointer + if(!m_boxFile.at(a->startOffset())) { + kdError(5003) << "KNFolder::loadArticle(KNLocalArticle *a) : cannot set mbox file-pointer!" << endl; + closeFiles(); + return false; + } + + //read content + m_boxFile.readLine(); //skip X-KNode-Overview + + unsigned int size=a->endOffset()-m_boxFile.at()-1; + QCString buff(size+10); + int readBytes=m_boxFile.readBlock(buff.data(), size); + closeFiles(); + if(readBytes < (int)(size) && m_boxFile.status() != IO_Ok) { //cannot read file + kdError(5003) << "KNFolder::loadArticle(KNLocalArticle *a) : corrupted mbox file, IO-error!" << endl; + return false; + } + + //set content + buff.at(readBytes)='\0'; //terminate string + 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(IO_WriteOnly | IO_Append)) { + kdError(5003) << "KNFolder::saveArticles() : cannot open mbox-file!" << endl; + closeFiles(); + return false; + } + + int addCnt=0; + bool ret=true; + bool clear=false; + QTextStream ts(&m_boxFile); + ts.setEncoding(QTextStream::Latin1); + + for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { + + clear=false; + if ( (*it)->id() == -1 || (*it)->collection() != this ) { + if ( (*it)->id() != -1 ) { + KNFolder *oldFolder = static_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 ); + } + if ( !append( (*it) ) ) { + kdError(5003) << "KNFolder::saveArticle(KNLocalArticle::List *l) : cannot append article!" << endl; + ret = false; + continue; + (*it)->setCollection(0); + } + else { + (*it)->setCollection(this); + addCnt++; + } + } + + if ( byId( (*it)->id() ) == (*it) ) { + + //MBox + ts << "From aaa@aaa Mon Jan 01 00:00:00 1997\n"; + (*it)->setStartOffset(m_boxFile.at()); //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"; + + (*it)->setEndOffset( m_boxFile.at() ); //save offset + + //update + ArticleWidget::articleChanged( (*it) ); + i_ndexDirty=true; + + } + else { + kdError(5003) << "KNFolder::saveArticle() : article not in folder!" << endl; + ret=false; + } + + if ( clear ) + (*it)->KMime::Content::clear(); + } + + closeFiles(); + syncIndex(); + + if(addCnt>0) { + c_ount=length(); + updateListItem(); + knGlobals.articleManager()->updateViewForCollection(this); + } + + return ret; +} + + +void KNFolder::removeArticles( KNLocalArticle::List &l, bool del ) +{ + if( !isLoaded() || l.isEmpty() ) + return; + + int idx = 0, delCnt = 0, *positions; + positions = new int[l.count()]; + KNLocalArticle *a = 0; + + for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) { + if ( (*it)->isLocked() ) + positions[idx] = -1; + else + positions[idx] = a_rticles.indexForId( (*it)->id() ); + } + + for ( idx = 0; idx < (int)(l.count()); ++idx ) { + if(positions[idx]==-1) + continue; + + a=at(positions[idx]); + + //update + knGlobals.artFactory->deleteComposerForArticle(a); + KNArticleWindow::closeAllWindowsForArticle(a); + ArticleWidget::articleRemoved( a ); + delete a->listItem(); + + //delete article + a_rticles.remove(positions[idx], del, false); + delCnt++; + if(!del) + a->setId(-1); + } + + if(delCnt>0) { + compact(); + c_ount-=delCnt; + updateListItem(); + i_ndexDirty=true; + } + delete[] positions; +} + + +void KNFolder::deleteAll() +{ + if(l_ockedArticles>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(IO_WriteOnly)) { + kdError(5003) << "KNFolder::syncIndex(bool force) : cannot open index-file!" << endl; + closeFiles(); + return; + } + + KNLocalArticle *a; + DynData d; + for(int idx=0; idx<length(); idx++) { + a=at(idx); + d.setData(a); + i_ndexFile.writeBlock((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 *a) +{ + id=a->id(); + so=a->startOffset(); + eo=a->endOffset(); + sId=a->serverId(); + ti=a->date()->unixTime(); + + 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 *a) +{ + a->setId(id); + a->date()->setUnixTime(ti); + 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]); +} + |