-/**************************************************************************
-* Copyright (C) 2003 by Hideki Ikemoto , (c)2004 by 421 *
-* ikemo@wakaba.jp *
+/***************************************************************************
+* Copyright (C) 2004 by Kita Developers *
+* ikemo@users.sourceforge.jp *
* *
* 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 *
* (at your option) any later version. *
***************************************************************************/
+/* DatManager manages all information about thread */
#include "datmanager.h"
-#include "qcp932codec.h"
-#include "comment.h"
-#include "access.h"
-#include "../part/kitaconfig.h"
-#include <qregexp.h>
-#include <qsemaphore.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QObject>
+#include <QtCore/QRegExp>
+#include <QtCore/QStringList>
+
+#include "boarddatabase.h"
+#include "cache.h"
+#include "datinfo.h"
+#include "kita_misc.h"
+#include "thread.h"
+#include "threadindex.h"
+#include "threadinfo.h"
using namespace Kita;
-/*---------------------------------------------------*/
+static const int DMANAGER_MAXQUEUE = 16;
-/* DatInfo stores information of *.dat */
+DatInfoList DatManager::m_datInfoList;
-DatInfo::DatInfo(const KURL& url):m_url(url){
- QString idstr;
- KURL logurl = url;
- logurl.setProtocol( "k2ch" );
- QString rawdata = Kita::Access::getCacheData(logurl);
- m_linedat.clear();
- m_subject = QString::null;
- m_maxNum = 0;
+/*-----------------------------------------------------------------------*/
+DatManager::DatManager(const KUrl& url) : m_url(url)
+{
+ m_datUrl = getDatUrl(url);
+ m_searchDatInfo = searchDatInfo();
+ m_datInfo = getDatInfo();
+}
- if(rawdata.length()){
- QCp932Codec codec;
- QString linedata = codec.toUnicode( rawdata );
- QStringList lines = QStringList::split( "\n", linedata );
- for ( QStringList::iterator it = lines.begin(); it != lines.end(); ++it, ++m_maxNum){
+/* create DatInfo explicitly. */
+/* Usually, DatInfo is NOT created
+ if cache does not exist(i.e. ReadNum == 0). */ /* public */
+bool DatManager::createDatInfo() const
+{
+ return getDatInfo(false /* don't check the existence of cache */) != 0;
+}
- /* copy dat */
- m_linedat += (*it);
- /* get id & copy */
- idstr = "none";
- QStringList list = QStringList::split( "<>", (*it), true );
- if ( list.size() == 5 ){
- /* copied from Comment::parseDateId */
- QRegExp regexp( "(\\d\\d)/(\\d\\d)/(\\d\\d) (\\d\\d):(\\d\\d)( ID:(.*))?" );
- if ( regexp.search( list[ 2 ] ) != -1 ) idstr = regexp.cap( 7 );
+/* get pointer of DatInfo */
- /* get subject */
- if ( m_subject == QString::null && list[4] != QString::null ) m_subject = list[ 4 ];
- }
- m_idlist += idstr;
- }
- }
+/* !!! NOTICE !!! */
+/* It is very dangerous to access to DatInfo directly. */
+/* Usually, access to it through DatManager. */ /* public */
+DatInfo * DatManager::getDatInfoPointer() const
+{
+ return m_datInfo;
}
-const QString& DatInfo::getDat(int num){
+/*------------------------------------------------------------------------*/
- if(num > m_maxNum) return QString::null;
-
- if(m_linedat.at(num-1) == m_linedat.end()) return QString::null;
- return *(m_linedat.at(num-1));
-}
+/* This function searches instance of DatInfo in m_datInfoList.
+
+ If cache exists, create DatInfo and return its pointer.
+
+ If checkCached == true and cache does not exist, return 0.
+
+ If checkCached == false and cache does not exist,
+ create DatInfo and return its pointer anyway.
+
+ see also DatManager::searchDatInfo() and DatManager::createDatInfo() */ /* private */
+DatInfo* DatManager::getDatInfo(bool checkCached) const
+{
+ /* search */
+ /* create and enroll instance */
+ return (m_searchDatInfo != 0)
+ ? m_searchDatInfo : enrollDatInfo(checkCached);
+}
-const QString& DatInfo::getId(int num){
- if(num > m_maxNum) return QString::null;
-
- if(m_idlist.at(num-1) == m_linedat.end()) return QString::null;
+/* This function just searches instance of DatInfo specified by datURL
+ without creating instance. */ /* private */
+DatInfo* DatManager::searchDatInfo() const
+{
+ if (m_datUrl.isEmpty())
+ return 0; /* This url is not enrolled in BoardManager. */
+ if (m_datInfoList.isEmpty())
+ return 0;
- return *(m_idlist.at(num-1));
-}
+ int i = 0;
+ DatInfoList::Iterator it;
+ DatInfo* datInfo;
+ for (it = m_datInfoList.begin(); it != m_datInfoList.end(); ++it, i++) {
-/*---------------------------------------------------*/
+ datInfo = (*it);
-/* DatManager manages *.dat. */
-/* Call
- Kita::DatManager::getHtml ,or
- Kita::DatManager::getDat
- in order to obtain data. */
+ if (m_datUrl == datInfo->url()) {
-DatInfoList DatManager::m_datInfo;
-QSemaphore DatManager::m_semap( 1 );
+ /* LRU */
+ if (i) {
+ m_datInfoList.erase(it);
+ m_datInfoList.prepend(datInfo);
+ }
-/* private */
-/* This function searches instance of DatInfo specified by url.
- If instance does not exist, create instance. */
-DatInfo* DatManager::getDatInfo(const KURL& url){
-
- m_semap++;
-
- if ( url.isEmpty() ){
- m_semap--;
- return NULL;
+ return datInfo;
+ }
}
-
- int i = 0;
- DatInfoList::Iterator it;
- /* search */
- if(m_datInfo.count()){
- for(it = m_datInfo.begin(); it != m_datInfo.end(); ++it, i++ ){
-
- if(url.host() == (*it)->url().host() &&
- url.path() == (*it)->url().path()){
-
- /* LRU */
- if(i){
- m_datInfo.remove(it);
- m_datInfo.prepend((*it));
- }
-
- m_semap--;
- return (*it);
- }
- }
- }
+ return 0;
+}
- /* not found */
- /*create new DatInfo and insert it into list. */
- KURL daturl = url.protocol()+"://"+url.host()+url.path();
+/* create and enroll the instance of DatInfo and delete old instances.
+ Note that DatInfo::DatInfo() opens cached data and reads it. */
+/* private */
+DatInfo* DatManager::enrollDatInfo(bool checkCached) const
+{
+ if (m_datUrl.isEmpty())
+ return 0; /* This url is not enrolled in BoardManager. */
- DatInfo* datInfo;
- datInfo = new DatInfo(daturl);
- if(datInfo->getMaxResNumber() == 0){ /* cache does not exist */
- delete(datInfo);
+ /* create DatInfo & read cached data */
+ DatInfo* datInfo = new DatInfo(m_datUrl);
- m_semap--;
- return NULL;
+ /* Does cache exist ? */
+ /* If cache does not exist, delete DatInfo here. */
+ if (checkCached && datInfo->getReadNum() == 0) {
+ delete datInfo;
+ return 0;
}
-
- m_datInfo.prepend(datInfo);
-
- /* delete the last item of list */
- if(m_datInfo.count() > DMANAGER_MAXQUEUE){
- it = m_datInfo.fromLast();
- m_datInfo.remove(it);
-
- delete(*it);
+
+ m_datInfoList.prepend(datInfo);
+
+ /* delete the all old instances (LRU algorithm)*/
+ if (m_datInfoList.count() > DMANAGER_MAXQUEUE) {
+ for (int i = DMANAGER_MAXQUEUE; i < m_datInfoList.count(); i++) {
+ DatInfo* deleteInfo = m_datInfoList.at(i);
+ if (deleteInfo == 0)
+ continue;
+ m_datInfoList.removeAt(i);
+ i--;
+ delete datInfo;
+ }
}
- m_semap--;
return datInfo;
}
/* public */
-void DatManager::deleteDat(const KURL& url){
- m_semap++;
-
- DatInfoList::Iterator it;
+void DatManager::deleteAllDatInfo()
+{
+ while (!m_datInfoList.isEmpty())
+ delete m_datInfoList.takeFirst();
+}
+
+
+
+/*-------------------------------------------------------------*/
+
+
- for(it = m_datInfo.begin(); it != m_datInfo.end(); ++it){
- if(url.host() == (*it)->url().host() &&
- url.path() == (*it)->url().path()){
- m_datInfo.remove(it);
- delete(*it);
+/* update cache */ /* public */
+bool DatManager::updateCache(const QObject* parent) const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->updateCache(parent);
+}
+
+
+/* public */
+int DatManager::getResponseCode() const
+{
+ return (m_datInfo == 0) ? 0 : m_datInfo->getResponseCode();
+}
+
+/* public */
+int DatManager::getServerTime() const
+{
+ return (m_datInfo == 0) ? 0 : m_datInfo->getServerTime();
+}
- m_semap--;
- return;
- }
+
+/* public */
+bool DatManager::deleteCache() const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ if (thread == 0)
+ return false;
+ if (thread->readNum() == 0)
+ return false;
+
+ /* init DatInfo */
+ if (m_searchDatInfo && !m_searchDatInfo->deleteCache()) {
+ return false;
}
- m_semap--;
+ /* reset readNum & veiwPos */
+ thread->setReadNum(0);
+ thread->setViewPos(0);
+
+ /* delete cache */
+ Cache cache(m_datUrl);
+ QString cachePath = cache.getPath();
+ QString indexPath = cache.getIndexPath();
+ QFile::remove(indexPath);
+ QFile::remove(cachePath);
+
+ /* delete log from "cache" */
+ ThreadInfo::removeThreadInfo(m_datUrl.prettyUrl());
+ return true;
}
/* public */
-const QString& DatManager::getDat(const KURL& url, int num){
- DatInfo* datInfo = getDatInfo(url);
- if(datInfo == NULL) return QString::null;
+bool DatManager::isLoadingNow() const
+{
+ return (m_searchDatInfo == 0) ? false : m_searchDatInfo->isLoadingNow();
+}
+
- return datInfo->getDat(num);
+/* public */
+void DatManager::stopLoading() const
+{
+ if (m_searchDatInfo == 0)
+ return;
+ m_searchDatInfo->stopLoading();
}
+/*--------------------------------------*/
+/* string data */
+
+
/* public */
-const QString& DatManager::getSubject(const KURL& url){
- DatInfo* datInfo = getDatInfo(url);
- if(datInfo == NULL) return QString::null;
+QString DatManager::getDat(int num) const
+{
+ return (m_datInfo == 0) ? QString() : m_datInfo->getDat(num);
+}
+
- return datInfo->getSubject();
+
+/* public */
+QString DatManager::getId(int num) const
+{
+ return (m_datInfo == 0) ? QString() : m_datInfo->getId(num);
}
/* public */
-int DatManager::getNumByID(const KURL& url, QString strid ){
+QString DatManager::getPlainName(int num) const
+{
+ return (m_datInfo == 0) ? QString() : m_datInfo->getPlainName(num);
+}
- DatInfo* datInfo = getDatInfo(url);
- if(datInfo == NULL) return 0;
-
- int num = 0;
- int maxNum = datInfo->getMaxResNumber();
- for ( int i = 1; i <= maxNum; i++ ) {
- if(datInfo->getId(i) == strid) num ++;
- }
+/* public */
+QString DatManager::getPlainBody(int num) const
+{
+ return (m_datInfo == 0) ? QString() : m_datInfo->getPlainBody(num);
+}
+
- return num;
+/* public */
+QString DatManager::getPlainTitle(int num) const
+{
+ return (m_datInfo == 0) ? QString() : m_datInfo->getPlainTitle(num);
+}
+
+
+/* get name (i.e. subject) of thread from URL of dat file. */ /* public */
+QString DatManager::threadName() const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ return (thread != 0) ? thread->threadName() : QString();
}
/* public */
-int DatManager::getMaxResNumber(const KURL& url){
- DatInfo* datInfo = getDatInfo(url);
- if(datInfo == NULL) return 0;
+QString DatManager::threadId() const
+{
+ return m_datUrl.fileName().section('.', 0, 0);
+}
+
+/*---------------------------------------*/
+/* HTML data */
- return datInfo->getMaxResNumber();
+/* public */
+QString DatManager::getHtml(int startnum, int endnum, bool checkAbone) const
+{
+ return (m_datInfo == 0)
+ ? QString() : m_datInfo->getHTMLString(startnum, endnum, checkAbone);
}
+
/* public */
-QString DatManager::getHtml(const KURL& url, int startnum, int endnum ){
+QString DatManager::getHtmlById(const QString& strid, int &count) const
+{
+ return (m_datInfo == 0) ? QString() : m_datInfo->getHtmlById(strid, count);
+}
- DatInfo* datInfo = getDatInfo(url);
- if(datInfo == NULL) return QString::null;
-
- QString retstr = QString::null ;
- bool showAddr = KitaConfig::showMailAddress();
- for(int num = startnum; num <= endnum; num++){
-
- QString line = datInfo->getDat(num);
- if(line != QString::null){
+/* Get HTML document of res tree.*/ /* public */
+QString DatManager::getTreeByRes(int rootnum, int &count) const
+{
+ return (m_datInfo == 0)
+ ? QString() : m_datInfo->getTreeByRes(rootnum, count);
+}
- Kita::Comment comment( line );
+/* Get HTML document of reverse res tree.*/ /* public */
+QString DatManager::getTreeByResReverse(int rootnum, int &count) const
+{
+ return (m_datInfo == 0)
+ ? QString() : m_datInfo->getTreeByResReverse(rootnum, count);
+}
- /* check abone */
- if(checkAbone(datInfo->getId(num),ABONECHK_BY_ID)) continue;
- if(checkAbone(comment.getName(),ABONECHK_BY_NAME)) continue;
- if(checkAbone(comment.getBody(),ABONECHK_BY_WORD)) continue;
-
- retstr += comment.toHtml( num, showAddr );
- }
- }
- return retstr;
+/* public */
+int DatManager::getResNum() const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ return (thread != 0) ? thread->resNum() : 0;
}
-/* public */ /* This function is also called by kitadomtree. */
-bool DatManager::checkAbone(const QString& str, int mode)
+/* public */
+int DatManager::getReadNum() const
{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ return (thread != 0) ? thread->readNum() : 0;
+}
- QStringList &strlist = KitaConfig::aboneIDList();
- switch(mode){
- case ABONECHK_BY_ID: break;
- case ABONECHK_BY_NAME: strlist = KitaConfig::aboneNameList(); break;
- case ABONECHK_BY_WORD: strlist = KitaConfig::aboneWordList(); break;
- default: return FALSE;
- }
- int i = -1;
- for ( QStringList::iterator it = strlist.begin();
- it != strlist.end(); ++it ) {
- i = str.find( ( *it ) );
- if ( i != -1 ){
- return TRUE;
- }
+/* public */
+int DatManager::getViewPos() const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ return (thread != 0) ? thread->viewPos() : 0;
+}
+
+
+/* public */
+void DatManager::setViewPos(int num) const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ if (thread != 0)
+ thread->setViewPos(num);
+
+ /* save idx */
+ ThreadIndex threadIndex(m_url);
+ threadIndex.setViewPos(num);
+
+ /* save "cache" */
+ ThreadInfo::setReadNum(m_datUrl.prettyUrl(), num);
+}
+
+
+/* public */
+int DatManager::getDatSize() const
+{
+ return (m_datInfo == 0) ? 0 : m_datInfo->getDatSize();
+}
+
+/* get number of responses which have same ID. */ /* public */
+int DatManager::getNumById(const QString& strid) const
+{
+ return (m_datInfo == 0) ? 0 : m_datInfo->getNumById(strid);
+}
+
+
+/* public */
+bool DatManager::isThreadEnrolled() const
+{
+ return !m_datUrl.isEmpty();
+}
+
+
+/* public */
+bool DatManager::is2chThread() const
+{
+ BoardDatabase db(m_url);
+ if (db.type() != Board_2ch)
+ return false;
+ if (m_datUrl.isEmpty())
+ return false;
+
+ QRegExp url_2ch(".*\\.2ch\\.net");
+ QRegExp url_bbspink(".*\\.bbspink\\.com");
+
+ if (url_2ch.indexIn(m_url.host()) != -1
+ || url_bbspink.indexIn(m_url.host()) != -1)
+ return true;
+
+ return false;
+}
+
+
+/* public */
+bool DatManager::isResValid(int num) const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->isResValid(num);
+}
+
+
+/* public */
+bool DatManager::isBroken() const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->isBroken();
+}
+
+/* public */
+bool DatManager::isResBroken(int num) const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->isResBroken(num);
+}
+
+
+
+/* check if ID == strid */ /* public */
+bool DatManager::checkId(const QString& strid, int num) const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->checkId(strid, num);
+}
+
+
+/* check if keywords are included */ /* public */
+bool DatManager::checkWord(const QStringList& strlist, int num,
+ bool checkOr /* AND or OR search */) const
+{
+ return (m_datInfo == 0)
+ ? false : m_datInfo->checkWord(strlist, num, checkOr);
+}
+
+
+/* public */
+bool DatManager::isMarked(int num) const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ return (thread == 0) ? false : thread->isMarked(num);
+}
+
+
+/* public */
+void DatManager::setMark(int num, bool mark) const
+{
+ Thread* thread = Thread::getByUrlNew(m_datUrl);
+ if (thread == 0)
+ return;
+
+ if (thread->setMark(num, mark)) {
+ ThreadIndex threadIndex(m_url);
+ threadIndex.setMarkList(thread->markList());
}
+}
+
+
+/* public */
+bool DatManager::checkAbone(int num) const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->checkAbone(num);
+}
+
+
+/* public */
+void DatManager::resetAbone() const
+{
+ if (m_datInfo == 0)
+ return;
+ m_datInfo->resetAbone();
+}
- return FALSE;
+
+/* check if the thread is shown on the main thread tab. */ /* public */
+bool DatManager::isMainThreadOpened() const
+{
+ return (m_datInfo == 0) ? false : m_datInfo->isOpened();
+}
+
+void DatManager::setMainThreadOpened(bool isOpened) const
+{
+ if (m_datInfo == 0)
+ return;
+ m_datInfo->setOpened(isOpened);
+}
+
+
+/*--------------------------*/
+/* obsolete */
+
+/* public */
+QString DatManager::threadUrl() const
+{
+ return getThreadUrl(m_url);
}