OSDN Git Service

remove useless? code.
[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
476     /* open and read subject.txt */
477     readSubjectTxt( bdata, url, threadList );
478
479     /* get old logs */
480     if ( oldLogs ) {
481
482         QPtrList< Thread > tmpList;
483         tmpList.clear();
484         getCachedThreadList( url, tmpList );
485
486         for ( unsigned i = 0; i < tmpList.count(); i++ ) {
487
488             if ( threadList.contains( tmpList.at( i ) ) == 0 ) oldLogList.append( tmpList.at( i ) );
489         }
490     }
491 }
492
493
494 /* read the cache dir & get the list of all threads. */ /* private */ /* static */
495 void BoardManager::getCachedThreadList( const KURL& url, QPtrList< Thread >& threadList )
496 {
497     QString cacheDir = Cache::baseDir() + Cache::serverDir( url ) + Cache::boardDir( url );
498     QDir d( cacheDir );
499     if ( d.exists() ) {
500
501         /* get all file names */
502         QString ext = BoardManager::getBoardData( url ) ->ext();
503         QString boardURL = BoardManager::getBoardData( url ) ->basePath();
504         QStringList flist = d.entryList( "*" + ext );
505
506         for ( QStringList::iterator it = flist.begin(); it != flist.end(); ++it ) {
507             if ( ( *it ) == QString::null ) continue;
508
509             QString datURL = boardURL + "dat/" + ( *it );
510
511             /* read idx file */
512             Kita::Thread* thread = Kita::Thread::getByURLNew( datURL );
513             if ( thread == NULL ) {
514
515                 thread = Kita::Thread::getByURL( datURL );
516                 if ( thread == NULL ) continue;
517                 ThreadIndex::loadIndex( thread, datURL, FALSE );
518             }
519
520             if ( thread != NULL ) threadList.append( thread );
521         }
522     }
523 }
524
525
526
527 /* open subject.txt and get list of Thread classes */ /* private */ /* static */
528 bool BoardManager::readSubjectTxt( BoardData* bdata, const KURL& url, QPtrList< Thread >& threadList )
529 {
530     /* get all names of cached files to read idx.  */
531     QStringList cacheList;
532     if ( !bdata->readIdx() ) {
533
534         QString cacheDir = Cache::baseDir() + Cache::serverDir( url ) + Cache::boardDir( url );
535         QDir d( cacheDir );
536         if ( d.exists() ) {
537             QString ext = BoardManager::getBoardData( url ) ->ext();
538             cacheList = d.entryList( "*" + ext );
539         }
540     }
541
542     /* open subject.txt */
543     QString subjectPath = Cache::getSubjectPath( url );
544     QIODevice * device = KFilterDev::deviceForFile( subjectPath, "application/x-gzip" );
545     if ( !device->open( IO_ReadOnly ) ) return FALSE;
546
547     QTextStream stream( device );
548
549     if ( BoardManager::type( url ) == Board_JBBS ) {
550         if ( !m_eucJpCodec ) m_eucJpCodec = new QEucJpCodec();
551         stream.setCodec( m_eucJpCodec );
552     } else {
553         if ( !m_cp932Codec ) m_cp932Codec = new QCp932Codec();
554         stream.setCodec( m_cp932Codec );
555     }
556
557     // parse subject.txt(only one format...)
558     // FIXME: need to refactoring
559     QRegExp regexp;
560     switch ( BoardManager::type( url ) ) {
561
562     case Board_MachiBBS:
563     case Board_JBBS:
564         regexp.setPattern( "(\\d+\\.cgi),(.*)\\((\\d+)\\)" );
565         break;
566
567     default:
568         regexp.setPattern( "(\\d+\\.dat)<>(.*)\\((\\d+)\\)" );
569         break;
570     }
571     QString line;
572
573     while ( ( line = stream.readLine() ) != QString::null ) {
574         int pos = regexp.search( line );
575         if ( pos != -1 ) {
576             QString fname = regexp.cap( 1 );
577             QString subject = regexp.cap( 2 );
578             QString num = regexp.cap( 3 );
579
580             /* get pointer of Thread class */
581             QString datURL = boardURL( url ) + "dat/" + fname;
582             Kita::Thread* thread = Kita::Thread::getByURL( datURL );
583             if ( threadList.find( thread ) == -1 ) {
584                 threadList.append( thread );
585             }
586
587             /* set thread name */
588             thread->setThreadName( subject );
589
590             /* load index file */
591             if ( !bdata->readIdx() ) {
592
593                 if ( cacheList.contains( fname ) ) ThreadIndex::loadIndex( thread, datURL, FALSE );
594             }
595
596             /* update res num */
597             int newNum = num.toInt();
598             if ( thread->readNum() ) { /* cache exists */
599                 int oldNum = thread->resNum();
600
601                 if ( newNum > oldNum ) {
602                     Kita::ThreadIndex::setResNum( datURL, newNum );
603                 }
604             }
605             thread->setResNum( newNum );
606         }
607     }
608
609     device->close();
610     bdata->setReadIdx( TRUE ); /* never read idx files again */
611
612     return TRUE;
613 }
614
615 /*---------------------------*/
616 /* BoardData */
617
618 /* reset all BoardData */ /* public */ /* static */
619 void BoardManager::clearBoardData()
620 {
621     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it )
622         delete( *it );
623
624     m_boardDataList.clear();
625     m_previousBoardData = NULL;
626     m_previousBoardURL = QString::null;
627 }
628
629 /**
630  *
631  * @param[in] board
632  * @param[in] boardName
633  * @param[in] type
634  * @param[in] test
635  *
636  * @param[out] oldURL
637  *
638  * @retval Board_enrollEnrolled if board is already enrolled. oldURL is QString::null.
639  * @retval Board_enrollNew if board is new board. oldURL is QString::null.
640  * @retval Board_enrollMoved if board is moved. oldURL is old URL.
641  *
642  * @note board is NOT enrolled when board is moved.
643  * To enroll new URL, call BoardManager::moveBoard(). 
644  *
645  * "int type" is type of board. It could be "Kita::Board_Unknown". See also parseBoardURL().
646  * 
647  * If "bool test" is TRUE, this function just checks if the board is enrolled (never enroll board).
648  *
649  */ 
650 /* public */ /* static */
651 int BoardManager::enrollBoard( const KURL& url, const QString& boardName, QString& oldURL, int type, bool test )
652 {
653     QString hostname;
654     QString rootPath;
655     QString delimiter;
656     QString bbsPath;
657     QString ext;
658     type = parseBoardURL( url, type, hostname, rootPath, delimiter, bbsPath, ext );
659     oldURL = QString::null;
660
661     if ( type == Board_Unknown ) return Board_enrollFailed;
662
663     /* check if the board is enrolled or moved. */
664     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it ) {
665
666         if ( ( *it ) ->boardName() == boardName
667                 && ( *it ) ->type() == type
668                 && ( *it ) ->bbsPath() == bbsPath ) {
669
670             if ( ( *it ) ->hostName() == hostname
671                     && ( *it ) ->rootPath() == rootPath ) { /* enrolled */
672                 return Board_enrollEnrolled;
673             } else { /* moved */
674                 oldURL = ( *it ) ->basePath();
675                 return Board_enrollMoved;
676             }
677         }
678     }
679
680     /* test only */
681     if ( test ) return Board_enrollNew;
682
683     /* enroll new board */
684     BoardData* bdata = new BoardData( boardName, hostname, rootPath, delimiter, bbsPath, ext, type );
685     m_boardDataList.append( bdata );
686
687     return Board_enrollNew;
688 }
689
690
691 /* parse board URL      */
692 /* return board type.   */ /* private */ /* static */
693 int BoardManager::parseBoardURL(
694
695     /* input */
696     const KURL& url,
697     int type,   /* If type = Board_Unknown, type will be decided according to url. */
698
699     /* output */
700     QString& hostname,
701     QString& rootPath,
702     QString& delimiter,
703     QString& bbsPath,
704     QString& ext )
705 {
706     hostname = url.protocol() + "://" + url.host();
707     rootPath = QString::null;
708     delimiter = QString::null;
709     bbsPath = QString::null;
710     ext = QString::null;
711
712     /* decide type */
713     if ( type == Board_Unknown ) {
714
715         if ( url.host().contains( "machi.to" ) ) type = Board_MachiBBS;
716         else if ( url.host().contains( "jbbs.livedoor.jp" ) ) type = Board_JBBS;
717         else type = Board_2ch;
718     }
719
720     /* parse */
721     switch ( type ) {
722
723     case Board_MachiBBS:     /* MACHI : http:// *.machi.to/(bbsPath)/ */
724
725         delimiter = "/bbs/read.pl";
726         bbsPath = url.filename();
727         ext = ".cgi";
728         break;
729
730     case Board_JBBS:   /* JBBS : http://jbbs.livedoor.jp/(bbsPath)/ */
731
732         delimiter = "/bbs/read.cgi";
733         bbsPath = url.prettyURL().remove( hostname );
734         type = Board_JBBS;
735         ext = ".cgi";
736         break;
737
738     case Board_FlashCGI:  /* test for Flash CGI/Mini Thread  */
739
740         delimiter = "/test/read.cgi";
741         bbsPath = url.filename();
742         rootPath = url.prettyURL().remove( hostname + "/" ).remove( bbsPath + "/" );
743         if ( rootPath.length() == 0 ) rootPath = QString::null;
744         ext = ".dat";
745         break;
746
747     default:   /* 2ch : http://(hostname)/(rootPath)/(bbsPath)/ */
748
749         delimiter = "/test/read.cgi";
750         bbsPath = url.filename();
751         rootPath = url.prettyURL().remove( hostname + "/" ).remove( bbsPath + "/" );
752         if ( rootPath.length() == 0 ) rootPath = QString::null;
753         ext = ".dat";
754         type = Board_2ch;
755         break;
756     }
757
758     /* For example, if bbsPath = "linux/", then m_bbsPath = "/linux" */
759     const QRegExp exp( "/$" );
760     rootPath.remove( exp );
761     bbsPath.remove( exp );
762     if ( rootPath != QString::null && rootPath.at( 0 ) != '/' ) rootPath = "/" + rootPath;
763     if ( bbsPath != QString::null && bbsPath.at( 0 ) != '/' ) bbsPath = "/" + bbsPath;
764
765     return type;
766 }
767
768
769 /* public */ /* static */
770 bool BoardManager::isEnrolled( const KURL& url )
771 {
772     if ( getBoardData( url ) == NULL ) return FALSE;
773     return TRUE;
774 }
775
776
777 /* public */ /* static */
778 BoardData* BoardManager::getBoardData( const KURL& url )
779 {
780     if ( url.isEmpty() ) return NULL;
781     QString urlstr = url.prettyURL();
782
783     /* cache */
784     if ( m_previousBoardData != NULL && m_previousBoardURL == urlstr ) return m_previousBoardData;
785
786     for ( BoardDataList::Iterator it = m_boardDataList.begin(); it != m_boardDataList.end(); ++it ) {
787
788         int count = ( *it ) ->keyBasePathList().count();
789         for ( int i = 0; i < count ; ++i ) {
790             if ( urlstr.contains( ( *it ) ->keyBasePathList() [ i ] )
791                     || urlstr.contains( ( *it ) ->keyCgiBasePathList() [ i ] ) ) {
792
793                 /* cache */
794                 m_previousBoardData = ( *it );
795                 m_previousBoardURL = urlstr;
796
797                 return ( *it );
798             }
799         }
800     }
801
802     return NULL;
803 }
804
805
806
807 /*--------------------------------*/
808 /* BBSHISTORY */
809
810
811 /* load the bbs history file ( BBSHISTORY ), and create keys of Data Base.  */
812 /* Before calling this, enroll the board by enrollBoard().                  */
813 /*
814     ex) If the host of board moved like :
815  
816     http:://aaa.com -> http://bbb.com -> http://ccc.com -> http://ddd.com
817     
818     then, BBSHISTORY is
819  
820     http://ccc.com
821     http://bbb.com
822     http://aaa.com
823  
824 */ /* public */ /* static */
825 bool BoardManager::loadBBSHistory( const KURL& url )
826 {
827     BoardData * bdata = getBoardData( url );
828     if ( bdata == NULL ) return FALSE;
829
830     QStringList keyHosts = bdata->hostName();
831
832     QFile file( Cache::getBBSHistoryPath( url ) );
833     if ( file.open( IO_ReadOnly ) ) {
834
835         QTextStream ts( &file );
836
837         QString line;
838         while ( !ts.eof() ) {
839
840             line = ts.readLine();
841             keyHosts += line;
842         }
843
844         bdata->createKeys( keyHosts );
845         file.close();
846
847         return TRUE;
848     }
849
850     return FALSE;
851 }
852
853
854 /* public */ /* static */
855 bool BoardManager::moveBoard( const KURL& fromURL, const KURL& toURL )
856 {
857     QString oldhost = fromURL.protocol() + "://" + fromURL.host();
858     QString newhost = toURL.protocol() + "://" + toURL.host();
859
860     const QRegExp exp( "/$" );
861     QString oldURL = fromURL.prettyURL();
862     QString newURL = toURL.prettyURL();
863     oldURL.remove( exp );
864     newURL.remove( exp );
865     oldURL += "/";
866     newURL += "/";
867
868     if ( oldURL == newURL ) return FALSE;
869
870     /* Is oldURL enrolled? */
871     BoardData* bdata = getBoardData( oldURL );
872     if ( bdata == NULL ) {
873
874         /* Is newURL enrolled? */
875         bdata = getBoardData( newURL );
876         if ( bdata == NULL ) return FALSE;
877     }
878
879
880     /*---------------------------*/
881     /* update BoardData */
882
883     /* get the path of old cache */
884     bdata->setHostName( oldhost );
885     QStringList keyHosts = bdata->keyHostList();
886     keyHosts.remove( oldhost );
887     keyHosts.prepend( oldhost );
888     bdata->createKeys( keyHosts );
889     QString oldCachePath = Cache::baseDir() + Cache::serverDir( bdata->basePath() )
890                            + Cache::boardDir( bdata->basePath() );
891
892     /* update URL */
893     bdata->setHostName( newhost );
894
895     /* update keys */
896     /* The order of keyHosts will be like this:
897        
898       newhost      
899       oldhost      
900       foohost1
901       foohost2
902       
903     */
904     keyHosts = bdata->keyHostList();
905     keyHosts.remove( oldhost );
906     keyHosts.prepend( oldhost );
907     keyHosts.remove( newhost );
908     keyHosts.prepend( newhost );
909     bdata->createKeys( keyHosts );
910
911     /* reset BoardData */
912     bdata->setReadIdx( FALSE );
913     bdata->setSettingLoaded( FALSE );
914
915
916     /*---------------------------*/
917     /* move cache dir */
918
919     QDir qdir;
920     if ( ! qdir.exists( oldCachePath ) ) return TRUE;
921
922     /* mkdir new server dir */
923     QString newCachePath = Cache::baseDir() + Cache::serverDir( bdata->basePath() );
924     Kita::mkdir( newCachePath );
925
926     /* backup old dir */
927     newCachePath += Cache::boardDir( bdata->basePath() );
928     if ( qdir.exists ( newCachePath ) ) {
929         QString bkupPath = newCachePath;
930         bkupPath.truncate( bkupPath.length() - 1 ); /* remove '/' */
931         bkupPath += "." + QString().setNum( QDateTime::currentDateTime().toTime_t() );
932         qdir.rename( newCachePath, bkupPath );
933     }
934
935     /* move cache dir */
936     if ( qdir.exists( oldCachePath ) ) {
937         qdir.rename( oldCachePath, newCachePath );
938     } else Kita::mkdir( newCachePath );
939
940     /* make old dir */
941     if ( ! qdir.exists( oldCachePath ) ) {
942         Kita::mkdir( oldCachePath );
943         /* create BBS_MOVED */
944         QString movedPath = oldCachePath + "/BBS_MOVED";
945         QFile file( movedPath );
946         if ( file.open( IO_WriteOnly ) ) {
947             QTextStream stream( &file );
948             stream << newURL << endl;
949         }
950         file.close();
951     }
952
953     /*---------------------------*/
954     /* update BBSHISTRY */
955
956     QFile file( Cache::getBBSHistoryPath( bdata->basePath() ) );
957     if ( file.open( IO_WriteOnly ) ) {
958
959         QTextStream ts( &file );
960
961         keyHosts.remove( newhost );
962         for ( QStringList::iterator it = keyHosts.begin() ; it != keyHosts.end(); ++it ) {
963             ts << ( *it ) << endl;
964         }
965
966         file.close();
967     }
968
969
970     /*---------------------------*/
971     /* update other information */
972     FavoriteThreads::replace( oldURL, newURL );
973     Kita::Thread::replace( oldURL, newURL );
974     KitaThreadInfo::replace( oldURL, newURL );
975     Kita::FavoriteBoards::replace( oldURL, newURL );
976
977     return TRUE;
978 }