OSDN Git Service

remove code for KDE 3.1.x
[kita/kita.git] / kita / src / libkita / boardmanager.cpp
1 /***************************************************************************
2 *   Copyright (C) 2004 by Kita Developers                                 *
3 *   ikemo@users.sourceforge.jp                                            *
4 *                                                                         *
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 ***************************************************************************/
10
11 #include "boardmanager.h"
12 #include "qcp932codec.h"
13 #include "downloadmanager.h"
14 #include "cache.h"
15 #include "favoritethreads.h"
16 #include "thread.h"
17 #include "threadinfo.h"
18 #include "favoriteboards.h"
19 #include "kita_misc.h"
20 #include "threadindex.h"
21
22 #include <config.h>  /* VERSION */
23
24 #include <kdebug.h>
25 #include <kio/netaccess.h>
26 #include <kfilterdev.h>
27 #include <kio/slaveconfig.h>
28 #include <kdeversion.h>
29
30 #include <qfile.h>
31 #include <qdir.h>
32 #include <qregexp.h>
33 #include <qdatetime.h>
34 #include <qeucjpcodec.h>
35
36 using namespace Kita;
37
38
39 /*---------------------------------------------------------*/
40
41 /* BoardData */
42
43 BoardData::BoardData( const QString& boardName,
44                       const QString& hostname,
45                       const QString& rootPath,
46                       const QString& delimiter,
47                       const QString& bbsPath,
48                       const QString& ext,
49                       int boardtype )
50 {
51     m_readIdx = FALSE;
52     m_boardName = boardName;
53     m_rootPath = rootPath;
54     m_delimiter = delimiter;
55     m_bbsPath = bbsPath;
56     m_ext = ext;
57     m_type = boardtype;
58
59     /* set hostname and create URL of board */
60     setHostName( hostname );
61
62     /* create default key */
63     QStringList keyHosts = m_hostname;
64     createKeys( keyHosts );
65
66     /* reset SETTING.TXT */
67     setSettingLoaded( FALSE );
68 }
69
70 BoardData::~BoardData()
71 {}
72
73
74 /* public */
75 void BoardData::setHostName( const QString& hostName )
76 {
77     m_hostname = hostName;
78
79     /* m_basePath = (hostname)/(rootPath)/(bbsPath)/ */
80     m_basePath = m_hostname + m_rootPath + m_bbsPath + "/";
81
82     switch ( m_type ) {
83
84     case Board_MachiBBS:  /* m_cgiBasePath = (hostname)/(rootPath)/(delimiter)?BBS=(bbsPath) */
85         m_cgiBasePath = m_hostname + m_rootPath + m_delimiter + "?BBS=" + m_bbsPath.mid( 1 );
86         break;
87
88         /* m_cgiBasePath = (hostname)/(rootPath)/(delimiter)/(bbsPath)/ */
89     default:
90         m_cgiBasePath = m_hostname + m_rootPath + m_delimiter + m_bbsPath + "/";
91         break;
92     }
93 }
94
95
96 /*---------------------------*/
97 /* information */
98
99 /* public */
100 const bool BoardData::readIdx() const
101 {
102     return m_readIdx;
103 }
104
105 /* public */
106 void BoardData::setReadIdx( bool idx )
107 {
108     m_readIdx = idx;
109 }
110
111 /* public */
112 const QString& BoardData::boardName() const
113 {
114     return m_boardName;
115 }
116
117 /* public */
118 const QString& BoardData::hostName() const
119 {
120     return m_hostname;
121 }
122
123 /* public */
124 const QString& BoardData::rootPath() const
125 {
126     return m_rootPath;
127 }
128
129 /* public */
130 const QString& BoardData::delimiter() const
131 {
132     return m_delimiter;
133 }
134
135 /* public */
136 const QString& BoardData::bbsPath() const
137 {
138     return m_bbsPath;
139 }
140
141 /* public */
142 const QString& BoardData::ext() const
143 {
144     return m_ext;
145 }
146
147 /* public */
148 const int BoardData::type() const
149 {
150     return m_type;
151 }
152
153 /* public */
154 const QString& BoardData::basePath() const
155 {
156     return m_basePath;
157 }
158
159 /* public */
160 const QString& BoardData::cgiBasePath() const
161 {
162     return m_cgiBasePath;
163 }
164
165
166 /*---------------------------*/
167 /* SETTING.TXT */
168
169 /* public */
170 const QString BoardData::settingURL() const
171 {
172     return m_basePath + "SETTING.TXT";
173 }
174
175 /* public */
176 const bool BoardData::settingLoaded() const
177 {
178     return m_settingLoaded;
179 }
180
181 /* public */
182 const QString& BoardData::defaultName() const
183 {
184     return m_defaultName;
185 }
186
187 /* public */
188 const int BoardData::lineNum() const
189 {
190     return m_linenum;
191 }
192
193 /* public */
194 const int BoardData::msgCount() const
195 {
196     return m_msgCount;
197 }
198
199 /* public */
200 const KURL& BoardData::titleImgURL() const
201 {
202     return m_titleImgURL;
203 }
204
205 /* public */
206 void BoardData::setSettingLoaded( bool set )
207 {
208     m_settingLoaded = set;
209     if ( ! set ) {
210             m_defaultName = QString::null;
211             m_linenum = 0;
212             m_msgCount = 0;
213             m_titleImgURL = QString::null;
214         }
215 }
216
217 /* public */
218 void BoardData::setDefaultName( const QString& newName )
219 {
220     m_defaultName = newName;
221 }
222
223 /* public */
224 void BoardData::setLineNum( int newLine )
225 {
226     m_linenum = newLine;
227 }
228
229 /* public */
230 void BoardData::setMsgCount( int msgCount )
231 {
232     m_msgCount = msgCount;
233 }
234
235 /* public */
236 void BoardData::setTitleImgURL( const KURL& url )
237 {
238     m_titleImgURL = url;
239 }
240
241
242 /*---------------------------*/
243 /* keys */
244
245 /* create keys of DB */ /* public */
246 void BoardData::createKeys( const QStringList& keyHostList )
247 {
248     /* reset keys */
249     m_keyBasePathList.clear();
250     m_keyCgiBasePathList.clear();
251     m_keyHostList.clear();
252
253     m_keyHostList = keyHostList;
254
255     /* m_basePath = (hostname)/(rootPath)/(bbsPath)/ */
256     for ( unsigned int i = 0; i < m_keyHostList.count(); ++i ) {
257         if ( m_keyHostList[ i ].length() > 0 )
258             m_keyBasePathList += m_keyHostList[ i ] + m_rootPath + m_bbsPath + "/";
259     }
260
261     switch ( m_type ) {
262
263     case Board_MachiBBS:  /* m_cgiBasePath = (hostname)/(rootPath)/(delimiter)?BBS=(bbsPath) */
264         for ( unsigned int i = 0; i < m_keyHostList.count(); ++i )
265             m_keyCgiBasePathList += m_keyHostList[ i ] + m_rootPath + m_delimiter
266                                     + "?BBS=" + m_bbsPath.mid( 1 );
267         break;
268
269         /* m_cgiBasePath = (hostname)/(rootPath)/(delimiter)/(bbsPath)/ */
270     default:
271         for ( unsigned int i = 0; i < m_keyHostList.count(); ++i )
272             m_keyCgiBasePathList += m_keyHostList[ i ] + m_rootPath + m_delimiter + m_bbsPath + "/";
273         break;
274     }
275 }
276
277 /* public */
278 const QStringList& BoardData::keyHostList() const
279 {
280     return m_keyHostList;
281 }
282
283 /* public */
284 const QStringList& BoardData::keyBasePathList() const
285 {
286     return m_keyBasePathList;
287 }
288
289 /* public */
290 const QStringList& BoardData::keyCgiBasePathList() const
291 {
292     return m_keyCgiBasePathList;
293 }
294
295
296
297
298 /*---------------------------------------------------------------*/
299 /*---------------------------------------------------------------*/
300 /*---------------------------------------------------------------*/
301
302 /* BoardManager */
303
304 QCp932Codec* Kita::BoardManager::m_cp932Codec = NULL;
305 QEucJpCodec* Kita::BoardManager::m_eucJpCodec = NULL;
306 BoardDataList Kita::BoardManager::m_boardDataList;
307 BoardData* Kita::BoardManager::m_previousBoardData = NULL;
308 QString Kita::BoardManager::m_previousBoardURL;
309
310
311 BoardManager::BoardManager()
312 {
313     clearBoardData();
314 }
315
316
317 BoardManager::~BoardManager()
318 {
319     clearBoardData();
320 }
321
322 /* (hostname)/(rootPath)/(bbsPath)/ */ /* public */ /* static */
323 const QString BoardManager::boardURL( const KURL& url )
324 {
325     BoardData * bdata = getBoardData( url );
326     if ( bdata == NULL ) return QString::null;
327
328     return bdata->basePath();
329 }
330
331 /* public */ /* static */
332 const QStringList BoardManager::allBoardURLList()
333 {
334     QStringList urlList;
335     urlList.clear();
336
337     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it )
338         urlList += ( *it ) ->basePath();
339
340     return urlList;
341 }
342
343 /* (hostname)/(rootPath) */ /* public */ /* static */
344 const QString BoardManager::boardRoot( const KURL& url )
345 {
346     BoardData * bdata = getBoardData( url );
347     if ( bdata == NULL ) return QString::null;
348
349     return bdata->hostName() + bdata->rootPath();
350 }
351
352 /* (bbspath) */ /* public */ /* static */
353 const QString BoardManager::boardPath( const KURL& url )
354 {
355     BoardData * bdata = getBoardData( url );
356     if ( bdata == NULL ) return QString::null;
357
358     return bdata->bbsPath();
359 }
360
361 /* (ext) */ /* public */ /* static */
362 const QString BoardManager::ext( const KURL& url )
363 {
364     BoardData * bdata = getBoardData( url );
365     if ( bdata == NULL ) return QString::null;
366
367     return bdata->ext();
368 }
369
370 /* ID of board for writing */ /* public */ /* static */
371 const QString BoardManager::boardID( const KURL& url )
372 {
373     BoardData * bdata = getBoardData( url );
374     if ( bdata == NULL ) return QString::null;
375
376     return bdata->bbsPath().mid( 1 ); /* remove "/" */
377 }
378
379
380 /* (hostname)/(rootPath)/(bbsPath)/subject.txt */ /* public */ /* static */
381 const QString BoardManager::subjectURL( const KURL& url )
382 {
383     BoardData * bdata = getBoardData( url );
384     if ( bdata == NULL ) return QString::null;
385
386     return bdata->basePath() + "subject.txt";
387 }
388
389
390 /* public */ /* static */
391 const QString BoardManager::boardName( const KURL& url )
392 {
393     BoardData * bdata = getBoardData( url );
394     if ( bdata == NULL ) return QString::null;
395
396     return bdata->boardName();
397 }
398
399
400 /* public */ /* static */
401 const int BoardManager::type( const KURL& url )
402 {
403     BoardData * bdata = getBoardData( url );
404     if ( bdata == NULL ) return Board_Unknown;
405
406     return bdata->type();
407 }
408
409
410 /*---------------------------*/
411 /* ThreadList */
412
413
414 /*  get list of pointers of Thread classes.     */
415 /*
416   Input:
417  
418   url:  URL of board.
419   oldLogs: If TRUE, search cache and get list of pointer of old threads.
420   online: online or offline mode.
421  
422   Output:
423  
424   threadList: list of pointers of Thread classes.
425   oldLogList: list of pointers of old threads.
426  
427                                                  */ /* public */ /* static */
428 void BoardManager::getThreadList(
429
430     /* input */
431     const KURL& url,
432     bool oldLogs,
433     bool online,
434
435     /* output */
436     QPtrList< Thread >& threadList,
437     QPtrList< Thread >& oldLogList )
438 {
439     threadList.clear();
440     oldLogList.clear();
441
442     /* get all obtained threads list from cache */
443     if ( url.prettyURL() == "http://virtual/obtained/" ) {
444
445         QStringList bbslist = allBoardURLList();
446
447         /* search all cache dirs */
448         for ( QStringList::iterator it = bbslist.begin() ; it != bbslist.end(); ++it ) {
449
450             getCachedThreadList( ( *it ), threadList );
451         }
452
453         return ;
454     }
455
456     /*-------------------------*/
457
458     BoardData* bdata = getBoardData( url );
459     if ( bdata == NULL ) return ;
460
461     /* download subject.txt */
462     if ( online ) {
463
464         /* make directory */
465         QString cacheDir = Cache::baseDir() + Cache::serverDir( url ) + Cache::boardDir( url );
466         if ( !Kita::mkdir( cacheDir ) ) return ;
467
468         KIO::SlaveConfig::self() ->setConfigData( "http",
469                 url.host() ,
470                 "UserAgent",
471                 QString( "Monazilla/1.00 (Kita/%1)" ).arg( VERSION ) );
472         QString subjectPath = Cache::getSubjectPath( url );
473         KIO::NetAccess::download( subjectURL( url ), subjectPath, NULL );
474
475         /* download SETTING.TXT */
476         loadBBSSetting( url );
477     }
478
479     /* open and read subject.txt */
480     readSubjectTxt( bdata, url, threadList );
481
482     /* get old logs */
483     if ( oldLogs ) {
484
485         QPtrList< Thread > tmpList;
486         tmpList.clear();
487         getCachedThreadList( url, tmpList );
488
489         for ( unsigned i = 0; i < tmpList.count(); i++ ) {
490
491             if ( threadList.contains( tmpList.at( i ) ) == 0 ) oldLogList.append( tmpList.at( i ) );
492         }
493     }
494 }
495
496
497 /* read the cache dir & get the list of all threads. */ /* private */ /* static */
498 void BoardManager::getCachedThreadList( const KURL& url, QPtrList< Thread >& threadList )
499 {
500     QString cacheDir = Cache::baseDir() + Cache::serverDir( url ) + Cache::boardDir( url );
501     QDir d( cacheDir );
502     if ( d.exists() ) {
503
504         /* get all file names */
505         QString ext = BoardManager::getBoardData( url ) ->ext();
506         QString boardURL = BoardManager::getBoardData( url ) ->basePath();
507         QStringList flist = d.entryList( "*" + ext );
508
509         for ( QStringList::iterator it = flist.begin(); it != flist.end(); ++it ) {
510             if ( ( *it ) == QString::null ) continue;
511
512             QString datURL = boardURL + "dat/" + ( *it );
513
514             /* read idx file */
515             Kita::Thread* thread = Kita::Thread::getByURLNew( datURL );
516             if ( thread == NULL ) {
517
518                 thread = Kita::Thread::getByURL( datURL );
519                 if ( thread == NULL ) continue;
520                 ThreadIndex::loadIndex( thread, datURL, FALSE );
521             }
522
523             if ( thread != NULL ) threadList.append( thread );
524         }
525     }
526 }
527
528
529
530 /* open subject.txt and get list of Thread classes */ /* private */ /* static */
531 bool BoardManager::readSubjectTxt( BoardData* bdata, const KURL& url, QPtrList< Thread >& threadList )
532 {
533     /* get all names of cached files to read idx.  */
534     QStringList cacheList;
535     if ( !bdata->readIdx() ) {
536
537         QString cacheDir = Cache::baseDir() + Cache::serverDir( url ) + Cache::boardDir( url );
538         QDir d( cacheDir );
539         if ( d.exists() ) {
540             QString ext = BoardManager::getBoardData( url ) ->ext();
541             cacheList = d.entryList( "*" + ext );
542         }
543     }
544
545     /* open subject.txt */
546     QString subjectPath = Cache::getSubjectPath( url );
547     QIODevice * device = KFilterDev::deviceForFile( subjectPath, "application/x-gzip" );
548     if ( !device->open( IO_ReadOnly ) ) return FALSE;
549
550     QTextStream stream( device );
551
552     if ( BoardManager::type( url ) == Board_JBBS ) {
553         if ( !m_eucJpCodec ) m_eucJpCodec = new QEucJpCodec();
554         stream.setCodec( m_eucJpCodec );
555     } else {
556         if ( !m_cp932Codec ) m_cp932Codec = new QCp932Codec();
557         stream.setCodec( m_cp932Codec );
558     }
559
560     // parse subject.txt(only one format...)
561     // FIXME: need to refactoring
562     QRegExp regexp;
563     switch ( BoardManager::type( url ) ) {
564
565     case Board_MachiBBS:
566     case Board_JBBS:
567         regexp.setPattern( "(\\d+\\.cgi),(.*)\\((\\d+)\\)" );
568         break;
569
570     default:
571         regexp.setPattern( "(\\d+\\.dat)<>(.*)\\((\\d+)\\)" );
572         break;
573     }
574     QString line;
575
576     while ( ( line = stream.readLine() ) != QString::null ) {
577         int pos = regexp.search( line );
578         if ( pos != -1 ) {
579             QString fname = regexp.cap( 1 );
580             QString subject = regexp.cap( 2 );
581             QString num = regexp.cap( 3 );
582
583             /* get pointer of Thread class */
584             QString datURL = boardURL( url ) + "dat/" + fname;
585             Kita::Thread* thread = Kita::Thread::getByURL( datURL );
586             if ( threadList.find( thread ) == -1 ) {
587                 threadList.append( thread );
588             }
589
590             /* set thread name */
591             thread->setThreadName( subject );
592
593             /* load index file */
594             if ( !bdata->readIdx() ) {
595
596                 if ( cacheList.contains( fname ) ) ThreadIndex::loadIndex( thread, datURL, FALSE );
597             }
598
599             /* update res num */
600             int newNum = num.toInt();
601             if ( thread->readNum() ) { /* cache exists */
602                 int oldNum = thread->resNum();
603
604                 if ( newNum > oldNum ) {
605                     Kita::ThreadIndex::setResNum( datURL, newNum );
606                 }
607             }
608             thread->setResNum( newNum );
609         }
610     }
611
612     device->close();
613     bdata->setReadIdx( TRUE ); /* never read idx files again */
614
615     return TRUE;
616 }
617
618 /*---------------------------*/
619 /* BoardData */
620
621 /* reset all BoardData */ /* public */ /* static */
622 void BoardManager::clearBoardData()
623 {
624     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it )
625         delete( *it );
626
627     m_boardDataList.clear();
628     m_previousBoardData = NULL;
629     m_previousBoardURL = QString::null;
630 }
631
632 /**
633  *
634  * @param[in] board
635  * @param[in] boardName
636  * @param[in] type
637  * @param[in] test
638  *
639  * @param[out] oldURL
640  *
641  * @retval Board_enrollEnrolled if board is already enrolled. oldURL is QString::null.
642  * @retval Board_enrollNew if board is new board. oldURL is QString::null.
643  * @retval Board_enrollMoved if board is moved. oldURL is old URL.
644  *
645  * @note board is NOT enrolled when board is moved.
646  * To enroll new URL, call BoardManager::moveBoard(). 
647  *
648  * "int type" is type of board. It could be "Kita::Board_Unknown". See also parseBoardURL().
649  * 
650  * If "bool test" is TRUE, this function just checks if the board is enrolled (never enroll board).
651  *
652  */ 
653 /* public */ /* static */
654 int BoardManager::enrollBoard( const KURL& url, const QString& boardName, QString& oldURL, int type, bool test )
655 {
656     QString hostname;
657     QString rootPath;
658     QString delimiter;
659     QString bbsPath;
660     QString ext;
661     type = parseBoardURL( url, type, hostname, rootPath, delimiter, bbsPath, ext );
662     oldURL = QString::null;
663
664     if ( type == Board_Unknown ) return Board_enrollFailed;
665
666     /* check if the board is enrolled or moved. */
667     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it ) {
668
669         if ( ( *it ) ->boardName() == boardName
670                 && ( *it ) ->type() == type
671                 && ( *it ) ->bbsPath() == bbsPath ) {
672
673             if ( ( *it ) ->hostName() == hostname
674                     && ( *it ) ->rootPath() == rootPath ) { /* enrolled */
675                 return Board_enrollEnrolled;
676             } else { /* moved */
677                 oldURL = ( *it ) ->basePath();
678                 return Board_enrollMoved;
679             }
680         }
681     }
682
683     /* test only */
684     if ( test ) return Board_enrollNew;
685
686     /* enroll new board */
687     BoardData* bdata = new BoardData( boardName, hostname, rootPath, delimiter, bbsPath, ext, type );
688     m_boardDataList.append( bdata );
689
690     return Board_enrollNew;
691 }
692
693
694 /* parse board URL      */
695 /* return board type.   */ /* private */ /* static */
696 int BoardManager::parseBoardURL(
697
698     /* input */
699     const KURL& url,
700     int type,   /* If type = Board_Unknown, type will be decided according to url. */
701
702     /* output */
703     QString& hostname,
704     QString& rootPath,
705     QString& delimiter,
706     QString& bbsPath,
707     QString& ext )
708 {
709     hostname = url.protocol() + "://" + url.host();
710     rootPath = QString::null;
711     delimiter = QString::null;
712     bbsPath = QString::null;
713     ext = QString::null;
714
715     /* decide type */
716     if ( type == Board_Unknown ) {
717
718         if ( url.host().contains( "machi.to" ) ) type = Board_MachiBBS;
719         else if ( url.host().contains( "jbbs.livedoor.jp" ) ) type = Board_JBBS;
720         else type = Board_2ch;
721     }
722
723     /* parse */
724     switch ( type ) {
725
726     case Board_MachiBBS:     /* MACHI : http:// *.machi.to/(bbsPath)/ */
727
728         delimiter = "/bbs/read.pl";
729         bbsPath = url.filename();
730         ext = ".cgi";
731         break;
732
733     case Board_JBBS:   /* JBBS : http://jbbs.livedoor.jp/(bbsPath)/ */
734
735         delimiter = "/bbs/read.cgi";
736         bbsPath = url.prettyURL().remove( hostname );
737         type = Board_JBBS;
738         ext = ".cgi";
739         break;
740
741     case Board_FlashCGI:  /* test for Flash CGI/Mini Thread  */
742
743         delimiter = "/test/read.cgi";
744         bbsPath = url.filename();
745         rootPath = url.prettyURL().remove( hostname + "/" ).remove( bbsPath + "/" );
746         if ( rootPath.length() == 0 ) rootPath = QString::null;
747         ext = ".dat";
748         break;
749
750     default:   /* 2ch : http://(hostname)/(rootPath)/(bbsPath)/ */
751
752         delimiter = "/test/read.cgi";
753         bbsPath = url.filename();
754         rootPath = url.prettyURL().remove( hostname + "/" ).remove( bbsPath + "/" );
755         if ( rootPath.length() == 0 ) rootPath = QString::null;
756         ext = ".dat";
757         type = Board_2ch;
758         break;
759     }
760
761     /* For example, if bbsPath = "linux/", then m_bbsPath = "/linux" */
762     const QRegExp exp( "/$" );
763     rootPath.remove( exp );
764     bbsPath.remove( exp );
765     if ( rootPath != QString::null && rootPath.at( 0 ) != '/' ) rootPath = "/" + rootPath;
766     if ( bbsPath != QString::null && bbsPath.at( 0 ) != '/' ) bbsPath = "/" + bbsPath;
767
768     return type;
769 }
770
771
772 /* public */ /* static */
773 bool BoardManager::isEnrolled( const KURL& url )
774 {
775     if ( getBoardData( url ) == NULL ) return FALSE;
776     return TRUE;
777 }
778
779
780 /* public */ /* static */
781 BoardData* BoardManager::getBoardData( const KURL& url )
782 {
783     if ( url.isEmpty() ) return NULL;
784     QString urlstr = url.prettyURL();
785
786     /* cache */
787     if ( m_previousBoardData != NULL && m_previousBoardURL == urlstr ) return m_previousBoardData;
788
789     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it ) {
790
791         int count = ( *it ) ->keyBasePathList().count();
792         for ( int i = 0; i < count ; ++i ) {
793             if ( urlstr.contains( ( *it ) ->keyBasePathList() [ i ] )
794                     || urlstr.contains( ( *it ) ->keyCgiBasePathList() [ i ] ) ) {
795
796                 /* cache */
797                 m_previousBoardData = ( *it );
798                 m_previousBoardURL = urlstr;
799
800                 return ( *it );
801             }
802         }
803     }
804
805     return NULL;
806 }
807
808
809
810 /*--------------------------------*/
811 /* BBSHISTORY */
812
813
814 /* load the bbs history file ( BBSHISTORY ), and create keys of Data Base.  */
815 /* Before calling this, enroll the board by enrollBoard().                  */
816 /*
817     ex) If the host of board moved like :
818  
819     http:://aaa.com -> http://bbb.com -> http://ccc.com -> http://ddd.com
820     
821     then, BBSHISTORY is
822  
823     http://ccc.com
824     http://bbb.com
825     http://aaa.com
826  
827 */ /* public */ /* static */
828 bool BoardManager::loadBBSHistory( const KURL& url )
829 {
830     BoardData * bdata = getBoardData( url );
831     if ( bdata == NULL ) return FALSE;
832
833     QStringList keyHosts = bdata->hostName();
834
835     QFile file( Cache::getBBSHistoryPath( url ) );
836     if ( file.open( IO_ReadOnly ) ) {
837
838         QTextStream ts( &file );
839
840         QString line;
841         while ( !ts.eof() ) {
842
843             line = ts.readLine();
844             keyHosts += line;
845         }
846
847         bdata->createKeys( keyHosts );
848         file.close();
849
850         return TRUE;
851     }
852
853     return FALSE;
854 }
855
856
857 /* public */ /* static */
858 bool BoardManager::moveBoard( const KURL& fromURL, const KURL& toURL )
859 {
860     QString oldhost = fromURL.protocol() + "://" + fromURL.host();
861     QString newhost = toURL.protocol() + "://" + toURL.host();
862
863     const QRegExp exp( "/$" );
864     QString oldURL = fromURL.prettyURL();
865     QString newURL = toURL.prettyURL();
866     oldURL.remove( exp );
867     newURL.remove( exp );
868     oldURL += "/";
869     newURL += "/";
870
871     if ( oldURL == newURL ) return FALSE;
872
873     /* Is oldURL enrolled? */
874     BoardData* bdata = getBoardData( oldURL );
875     if ( bdata == NULL ) {
876
877         /* Is newURL enrolled? */
878         bdata = getBoardData( newURL );
879         if ( bdata == NULL ) return FALSE;
880     }
881
882
883     /*---------------------------*/
884     /* update BoardData */
885
886     /* get the path of old cache */
887     bdata->setHostName( oldhost );
888     QStringList keyHosts = bdata->keyHostList();
889     keyHosts.remove( oldhost );
890     keyHosts.prepend( oldhost );
891     bdata->createKeys( keyHosts );
892     QString oldCachePath = Cache::baseDir() + Cache::serverDir( bdata->basePath() )
893                            + Cache::boardDir( bdata->basePath() );
894
895     /* update URL */
896     bdata->setHostName( newhost );
897
898     /* update keys */
899     /* The order of keyHosts will be like this:
900        
901       newhost      
902       oldhost      
903       foohost1
904       foohost2
905       
906     */
907     keyHosts = bdata->keyHostList();
908     keyHosts.remove( oldhost );
909     keyHosts.prepend( oldhost );
910     keyHosts.remove( newhost );
911     keyHosts.prepend( newhost );
912     bdata->createKeys( keyHosts );
913
914     /* reset BoardData */
915     bdata->setReadIdx( FALSE );
916     bdata->setSettingLoaded( FALSE );
917
918
919     /*---------------------------*/
920     /* move cache dir */
921
922     QDir qdir;
923     if ( ! qdir.exists( oldCachePath ) ) return TRUE;
924
925     /* mkdir new server dir */
926     QString newCachePath = Cache::baseDir() + Cache::serverDir( bdata->basePath() );
927     Kita::mkdir( newCachePath );
928
929     /* backup old dir */
930     newCachePath += Cache::boardDir( bdata->basePath() );
931     if ( qdir.exists ( newCachePath ) ) {
932         QString bkupPath = newCachePath;
933         bkupPath.truncate( bkupPath.length() - 1 ); /* remove '/' */
934         bkupPath += "." + QString().setNum( QDateTime::currentDateTime().toTime_t() );
935         qdir.rename( newCachePath, bkupPath );
936     }
937
938     /* move cache dir */
939     if ( qdir.exists( oldCachePath ) ) {
940         qdir.rename( oldCachePath, newCachePath );
941     } else Kita::mkdir( newCachePath );
942
943     /* make old dir */
944     if ( ! qdir.exists( oldCachePath ) ) {
945         Kita::mkdir( oldCachePath );
946         /* create BBS_MOVED */
947         QString movedPath = oldCachePath + "/BBS_MOVED";
948         QFile file( movedPath );
949         if ( file.open( IO_WriteOnly ) ) {
950             QTextStream stream( &file );
951             stream << newURL << endl;
952         }
953         file.close();
954     }
955
956     /*---------------------------*/
957     /* update BBSHISTRY */
958
959     QFile file( Cache::getBBSHistoryPath( bdata->basePath() ) );
960     if ( file.open( IO_WriteOnly ) ) {
961
962         QTextStream ts( &file );
963
964         keyHosts.remove( newhost );
965         for ( QStringList::iterator it = keyHosts.begin() ; it != keyHosts.end(); ++it ) {
966             ts << ( *it ) << endl;
967         }
968
969         file.close();
970     }
971
972
973     /*---------------------------*/
974     /* update other information */
975     FavoriteThreads::replace( oldURL, newURL );
976     Kita::Thread::replace( oldURL, newURL );
977     KitaThreadInfo::replace( oldURL, newURL );
978     Kita::FavoriteBoards::replace( oldURL, newURL );
979
980     return TRUE;
981 }
982
983
984 /*--------------------------------*/
985 /* SETTING.TXT  */
986
987
988 /* public */ /* static */
989 bool BoardManager::loadBBSSetting( const KURL& url, bool reload )
990 {
991     /* Is board enrolled ? */
992     BoardData * bdata = getBoardData( url );
993     if ( bdata == NULL ) return FALSE;
994     if ( bdata->type() != Board_2ch ) return FALSE;
995
996     KURL settingURL = bdata->settingURL();
997     QString path = Cache::getSettingPath( url );
998
999     /* now loading */
1000     if ( DownloadManager::isLoadingNow( settingURL ) ) return FALSE;
1001
1002     /* already loaded */
1003     if ( bdata->settingLoaded() && !reload ) return TRUE;
1004
1005     /* reset names, linenum, etc. */
1006     bdata->setSettingLoaded( FALSE );
1007
1008     /* download SETTING.TXT.*/
1009     DownloadManager::download( settingURL, path );
1010     bdata->setSettingLoaded( TRUE );
1011
1012     return TRUE;
1013 }
1014
1015
1016 /* public */ /* static */
1017 QString BoardManager::getBBSDefaultName( const KURL& url )
1018 {
1019     BoardData * bdata = openSettingTxt( url );
1020     if ( bdata == NULL ) bdata = getBoardData( url );
1021     if ( bdata == NULL ) return "(default name)";
1022     if ( bdata->defaultName() == QString::null ) return "(default name)";
1023     return bdata->defaultName();
1024 }
1025
1026
1027 /* public */ /* static */
1028 int BoardManager::getBBSMaxLine( const KURL& url )
1029 {
1030     BoardData * bdata = openSettingTxt( url );
1031     if ( bdata == NULL ) bdata = getBoardData( url );
1032     if ( bdata == NULL ) return 0;
1033     return bdata->lineNum();
1034 }
1035
1036 /* public */ /* static */
1037 int BoardManager::getBBSMsgCount( const KURL& url )
1038 {
1039     BoardData * bdata = openSettingTxt( url );
1040     if ( bdata == NULL ) bdata = getBoardData( url );
1041     if ( bdata == NULL ) return 0;
1042     return bdata->msgCount();
1043 }
1044
1045
1046 /* public */ /* static */
1047 const KURL BoardManager::titleImgURL( const KURL& url )
1048 {
1049     BoardData * bdata = openSettingTxt( url );
1050     if ( bdata == NULL ) bdata = getBoardData( url );
1051     if ( bdata == NULL ) return QString::null;
1052     return bdata->titleImgURL();
1053 }
1054
1055 /* open local SETTING.TXT, then get names, linenum, etc. */ /* private */ /* static */
1056 BoardData* BoardManager::openSettingTxt( const KURL& url )
1057 {
1058     BoardData * bdata = getBoardData( url );
1059     if ( bdata == NULL ) return NULL;
1060     if ( !bdata->settingLoaded() ) return NULL;
1061     if ( DownloadManager::isLoadingNow( bdata->settingURL() ) ) return NULL;
1062     if ( bdata->defaultName() != QString::null ) return bdata;
1063
1064     QFile file( Cache::getSettingPath( url ) );
1065     if ( file.open( IO_ReadOnly ) ) {
1066
1067         QTextStream ts( &file );
1068         if ( m_cp932Codec == NULL ) m_cp932Codec = new QCp932Codec();
1069         ts.setCodec( m_cp932Codec );
1070
1071         QString line;
1072         while ( !ts.eof() ) {
1073
1074             line = ts.readLine();
1075
1076             /* default name */
1077             QString key = "BBS_NONAME_NAME=";
1078             if ( line.find( key ) != -1 ) bdata->setDefaultName( line.remove( key ) );
1079
1080             /* 0ch type */
1081             key = "NANASI_NAME=";
1082             if ( line.find( key ) != -1 ) bdata->setDefaultName( line.remove( key ) );
1083
1084             /* line number */
1085             key = "BBS_LINE_NUMBER=";
1086             if ( line.find( key ) != -1 ) bdata->setLineNum( line.remove( key ).toInt() * 2 );
1087
1088             /* msg count */
1089             key = "BBS_MESSAGE_COUNT=";
1090             if ( line.find( key ) != -1 ) bdata->setMsgCount( line.remove( key ).toInt() );
1091
1092             /* title image */
1093             key = "BBS_TITLE_PICTURE=";
1094             if ( line.find( key ) != -1 ) {
1095                 QString path = line.remove( key );
1096                 KURL titleImgURL = KURL( bdata->basePath(), path );
1097                 bdata->setTitleImgURL( titleImgURL );
1098             }
1099         }
1100
1101         file.close();
1102     }
1103
1104     if ( bdata->defaultName() == QString::null ) bdata->setDefaultName( "(default name)" );
1105
1106     return bdata;
1107 }