OSDN Git Service

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