1 /**************************************************************************
2 * Copyright (C) 2003 by Hideki Ikemoto , (c)2004 by 421 *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
11 #include "datmanager.h"
12 #include "qcp932codec.h"
15 #include "../part/kitaconfig.h"
16 #include "../part/kita-utf8.h"
18 #include <qsemaphore.h>
23 #define UTF16_BRACKET 0xFF1E /* > */
24 #define UTF16_0 0xFF10 /* 0 */
25 #define UTF16_9 0xFF19 /* 9 */
26 #define UTF16_EQ 0xFF1D /* = */
27 #define UTF16_COMMA 0xFF0C /* , */
29 #define KITA_RESDIGIT 4
31 /*---------------------------------------------------*/
33 /* DatInfo stores information of *.dat */
35 DatInfo::DatInfo( const KURL& url ) : m_url( url )
40 logurl.setProtocol( "k2ch" );
41 QString rawdata = Kita::Access::getCacheData( logurl );
43 m_subject = QString::null;
45 m_spacestr = QString::null;
48 if ( rawdata.length() ) {
50 QString linedata = codec.toUnicode( rawdata );
52 QStringList lines = QStringList::split( "\n", linedata );
53 for ( QStringList::iterator it = lines.begin(); it != lines.end(); ++it, ++m_maxNum ) {
60 QStringList list = QStringList::split( "<>", ( *it ), true );
61 if ( list.size() == 5 ) {
62 /* copied from Comment::parseDateId */
63 QRegExp regexp( "(\\d\\d)/(\\d\\d)/(\\d\\d) (\\d\\d):(\\d\\d)( ID:(.*))?" );
64 if ( regexp.search( list[ 2 ] ) != -1 ) idstr = regexp.cap( 7 );
67 if ( m_subject == QString::null && list[ 4 ] != QString::null ) m_subject = list[ 4 ];
75 const QString& DatInfo::getDat( int num )
78 if ( num > m_maxNum ) return QString::null;
80 if ( m_linedat.at( num - 1 ) == m_linedat.end() ) return QString::null;
82 return *( m_linedat.at( num - 1 ) );
86 const QString& DatInfo::getId( int num )
89 if ( num > m_maxNum ) return QString::null;
91 if ( m_idlist.at( num - 1 ) == m_linedat.end() ) return QString::null;
93 return *( m_idlist.at( num - 1 ) );
96 /* convert dat to HTML */
97 QString DatInfo::getHtml(int num){
99 QString retstr = QString::null;
100 QString line = getDat(num);
101 bool showAddr = KitaConfig::showMailAddress();
103 if(line != QString::null){
105 Kita::Comment comment( line );
108 if(DatManager::checkAbone(getId(num),ABONECHK_BY_ID)) return retstr;
109 if(DatManager::checkAbone(comment.getName(),ABONECHK_BY_NAME)) return retstr;
110 if(DatManager::checkAbone(comment.getBody(),ABONECHK_BY_WORD)) return retstr;
112 retstr = comment.toHtml( num, showAddr );
119 /* Check if No.num has anchors to No.target */
120 /* For exsample, if No.num has an anchor ">>target",
122 bool DatInfo::checkRes(const int target, const int num )
125 AncListMap::Iterator ancmapit = m_anclistmap.find(num);
127 /* If map is not set, then do parsing */
128 if(ancmapit == m_anclistmap.end() ){
130 QString line = getDat(num);
131 if(line == QString::null) return FALSE;
144 /* remove HTML tags */
145 QRegExp rex( "<[^>]*>" );
148 const QChar *chpt = line.unicode();
150 unsigned int length = line.length();
152 for ( i = 0 ; i < length ; i++ ) {
154 if( chpt[ i ].unicode() == UTF16_BRACKET ||
155 (chpt[ i] == '&' && chpt[ i+1] == 'g' && chpt[ i+2] == 't' && chpt[ i+3] == ';')){
157 while(DatManager::parseResAnchor(chpt+i,length-i,linkstr,refNum,pos)){
158 if(refNum[1] < refNum[0]) refNum[1] = refNum[0];
159 anctmp.from = refNum[0];
160 anctmp.to = refNum[1];
169 ancmapit = m_anclistmap.insert(num,anclist);
173 for ( AncList::iterator it = (*ancmapit).begin(); it != (*ancmapit).end(); ++it ){
174 if ( target >= (*it).from && target <= (*it).to ) return TRUE;
181 /* Get HTML document of res tree.*/
191 QString DatInfo::getTreeByRes(const int rootnum, int& num, QString prestr )
193 QString retstr = QString::null ;
195 int maxNum = getMaxResNumber();
196 QStringList strlists;
198 if(m_spacestr == QString::null){
199 QTextCodec * codec = QTextCodec::codecForName( "utf8" );
201 m_framestr1 = codec->toUnicode( KITAUTF8_FRAME1 ); /* | */
202 m_framestr2 = codec->toUnicode( KITAUTF8_FRAME2 ); /* |- */
203 m_framestr3 = codec->toUnicode( KITAUTF8_FRAME3 ); /* L */
206 /* find responses that refer to rootnum */
207 for ( int i = rootnum+1; i <= maxNum; i++ ){
208 if(checkRes(rootnum,i)){
210 strlists += QString().setNum( i );
214 /* make HTML document */
217 for ( QStringList::iterator it = strlists.begin(); it != strlists.end(); ++it ){
219 if((*it) == strlists.last()) tmpstr = m_framestr3;
220 else tmpstr = m_framestr2;
221 retstr += prestr + tmpstr + "<a href=\"#" + (*it) + "\">>>" + (*it) + "</a><br>";
223 /* call myself recursively */
224 if((*it) == strlists.last()) tmpstr = prestr + m_spacestr + m_spacestr + m_spacestr;
225 else tmpstr = prestr + m_framestr1 + m_spacestr;
227 retstr += getTreeByRes((*it).toInt(),tmpnum,tmpstr);
236 /*---------------------------------------------------*/
238 /* DatManager manages all information about *.dat. */
240 DatInfoList DatManager::m_datInfo;
241 QSemaphore DatManager::m_semap( 1 );
244 /* This function searches instance of DatInfo specified by url.
245 If instance does not exist, create instance. */
246 DatInfo* DatManager::getDatInfo( const KURL& url )
251 if ( url.isEmpty() ) {
257 DatInfoList::Iterator it;
260 if ( m_datInfo.count() ) {
261 for ( it = m_datInfo.begin(); it != m_datInfo.end(); ++it, i++ ) {
263 if ( url.host() == ( *it ) ->url().host() &&
264 url.path() == ( *it ) ->url().path() ) {
268 m_datInfo.remove( it );
269 m_datInfo.prepend( ( *it ) );
280 /*create new DatInfo and insert it into list. */
281 KURL daturl = url.protocol() + "://" + url.host() + url.path();
284 datInfo = new DatInfo( daturl );
285 if ( datInfo->getMaxResNumber() == 0 ) { /* cache does not exist */
292 m_datInfo.prepend( datInfo );
294 /* delete the last item of list */
295 if ( m_datInfo.count() > DMANAGER_MAXQUEUE ) {
296 it = m_datInfo.fromLast();
297 m_datInfo.remove( it );
308 void DatManager::deleteDat( const KURL& url )
312 DatInfoList::Iterator it;
314 for ( it = m_datInfo.begin(); it != m_datInfo.end(); ++it ) {
315 if ( url.host() == ( *it ) ->url().host() &&
316 url.path() == ( *it ) ->url().path() ) {
317 m_datInfo.remove( it );
330 const QString& DatManager::getDat( const KURL& url, int num )
332 DatInfo * datInfo = getDatInfo( url );
333 if ( datInfo == NULL ) return QString::null;
335 return datInfo->getDat( num );
339 const QString& DatManager::getSubject( const KURL& url )
341 DatInfo * datInfo = getDatInfo( url );
342 if ( datInfo == NULL ) return QString::null;
344 return datInfo->getSubject();
349 int DatManager::getNumByID( const KURL& url, const QString& strid )
352 DatInfo * datInfo = getDatInfo( url );
353 if ( datInfo == NULL ) return 0;
356 int maxNum = datInfo->getMaxResNumber();
358 for ( int i = 1; i <= maxNum; i++ ) {
359 if ( datInfo->getId( i ) == strid ) num ++;
367 int DatManager::getMaxResNumber( const KURL& url )
369 DatInfo * datInfo = getDatInfo( url );
370 if ( datInfo == NULL ) return 0;
372 return datInfo->getMaxResNumber();
377 QString DatManager::getHtml( const KURL& url, int startnum, int endnum )
380 DatInfo * datInfo = getDatInfo( url );
381 if ( datInfo == NULL ) return QString::null;
383 QString retstr = QString::null ;
385 for(int num = startnum; num <= endnum; num++)
386 retstr += datInfo->getHtml(num);
392 /* public */ /* This function is also called by kitadomtree. */
393 bool DatManager::checkAbone( const QString& str, int mode )
396 QStringList & strlist = KitaConfig::aboneIDList();
398 case ABONECHK_BY_ID: break;
399 case ABONECHK_BY_NAME: strlist = KitaConfig::aboneNameList(); break;
400 case ABONECHK_BY_WORD: strlist = KitaConfig::aboneWordList(); break;
401 default: return FALSE;
405 for ( QStringList::iterator it = strlist.begin();
406 it != strlist.end(); ++it ) {
407 i = str.find( ( *it ) );
418 QString DatManager::getHtmlByID(const KURL& url, const QString& strid, int &num ){
420 DatInfo* datInfo = getDatInfo(url);
421 if(datInfo == NULL) return QString::null;
423 QString retstr = QString::null ;
425 int maxNum = datInfo->getMaxResNumber();
427 for ( int i = 1; i <= maxNum; i++ ) {
428 if(datInfo->getId(i) == strid){
430 retstr += datInfo->getHtml(i);
439 bool DatManager::checkID(const KURL& url, const QString& strid, int num ){
441 DatInfo* datInfo = getDatInfo(url);
442 if(datInfo == NULL) return FALSE;
444 if(datInfo->getId(num) == strid) return TRUE;
450 /* check keywords */ /* public */
451 bool DatManager::checkWord(const KURL& url,
452 QStringList& stlist, int num,
453 bool checkOR /* AND or OR search */
456 DatInfo* datInfo = getDatInfo(url);
457 if(datInfo == NULL) return FALSE;
459 QString str_text = datInfo->getDat(num);
460 if(str_text == QString::null) return FALSE;
462 for ( QStringList::iterator it = stlist.begin(); it != stlist.end(); ++it ) {
464 if ( checkOR ) { /* OR */
465 if ( str_text.find( ( *it ), 0, FALSE ) != -1 ) {
469 if ( str_text.find( ( *it ), 0, FALSE ) == -1 ) return FALSE;
473 if ( checkOR ) return FALSE;
479 /*------------------------------------------*/
480 /* parsing function for anchor (>>number) */
481 /*------------------------------------------*/ /* public */
483 /* This fuction parses res-anchor.
485 For example, if cdat = ">12-20", then
492 This function is also called in KitaDomTree::createResAnchor. */
494 bool DatManager::parseResAnchor(
497 const QChar *cdat, const unsigned int length,
500 QString& linkstr, int* refNum, unsigned int& pos ){
503 static bool isHYPHEN( unsigned short c )
508 || ( c >= 0x2010 && c <= 0x2015 )
510 || ( c == 0xFF0D ) /* UTF8: 0xEFBC8D */
522 linkstr = QString::null;
527 /* check '>' twice */
528 for ( i = 0;i < 2;i++ ) {
530 if ( cdat[ pos ].unicode() == UTF16_BRACKET ) {
531 linkstr += cdat[ pos ];
533 } else if ( cdat[ pos ] == '&' && cdat[ pos + 1 ] == 'g' /* > */
534 && cdat[ pos + 2 ] == 't' && cdat[ pos + 3 ] == ';' ) {
543 if ( cdat[ pos ] == ',' || cdat[ pos ].unicode() == UTF16_COMMA ) {
551 if ( cdat[ pos ] == '=' || cdat[ pos ].unicode() == UTF16_EQ ) {
562 for ( i = 0 ; i < KITA_RESDIGIT + 1 && pos < length ; i++, pos++, ret = TRUE ) {
564 unsigned short c = cdat[ pos ].unicode();
566 if ( ( c < UTF16_0 || c > UTF16_9 )
567 && ( c < '0' || c > '9' )
568 && ( !LocalFunc::isHYPHEN( c )
569 || ( i == 0 && LocalFunc::isHYPHEN( c ) )
570 || ( hyphen && LocalFunc::isHYPHEN( c ) ) )
573 linkstr += cdat[ pos ];
575 if ( LocalFunc::isHYPHEN( c ) ) {
579 if ( c >= UTF16_0 ) c = '0' + cdat[ pos ].unicode() - UTF16_0;
580 refNum[hyphen] *= 10;
581 refNum[hyphen] += c - '0';
590 bool DatManager::checkRes(const KURL& url,const int target,const int num )
592 DatInfo* datInfo = getDatInfo(url);
593 if(datInfo == NULL) return FALSE;
595 return datInfo->checkRes(target,num);
600 QString DatManager::getTreeByRes(const KURL& url, const int resNum, int &num ){
602 DatInfo* datInfo = getDatInfo(url);
603 if(datInfo == NULL) return QString::null;
605 QString retstr = QString::null ;
608 QString tmp = QString().setNum( resNum );
609 retstr = "<a href=\"#" + tmp + "\">>>" + tmp + "</a><br>";
610 retstr += datInfo->getTreeByRes(resNum,num,"");