OSDN Git Service

VIPサービス以外の2ch互換掲示板の過去ログ取得にも対応
[gikonavigoeson/gikonavi.git] / BoardGroup.pas
1 unit BoardGroup;
2
3 interface
4
5 uses
6         Windows, SysUtils, Classes, ComCtrls, {HTTPApp,} YofUtils, IdGlobal,
7         ExternalBoardManager, ExternalBoardPlugInMain, StrUtils;
8
9 type
10         //\83\8a\83X\83g\82Ì\95\\8e¦\83A\83C\83e\83\80\91I\91ð
11         TGikoViewType = (gvtAll, gvtLog, gvtNew, gvtLive, gvtArch, gvtUser);
12         //\83\8a\83X\83g\82Ì\8fã\82°\89º\82°
13         TGikoAgeSage = (gasNone, gasAge, gasSage, gasNew, gasArch, gasNull);
14
15         TCategory = class;
16         TBoard = class;
17         TThreadItem = class;
18
19
20         // BBS \82Ì\83\8b\81[\83g
21         TBBS = class(TList)
22         private
23                 FTitle: string;
24                 FFilePath : string;                                             // \94Â\83\8a\83X\83g\82Ì\83p\83X
25                 FExpand: Boolean;
26                 FKubetsuChk: Boolean;                                   //\8di\8d\9e\82Ý\8e\9e\91å\95\8e\9a\8f¬\95\8e\9a\8bæ\95Ê
27                 FSelectText: string;                                    //\8di\8d\9e\82Ý\95\8e\9a\97ñ
28                 FShortSelectText: string;
29                 FIsBoardFileRead : Boolean;             // \94Â\83\8a\83X\83g\82Í\93Ç\82Ý\8d\9e\82Ü\82ê\82Ä\82¢\82é\82©\81H
30
31                 function GetCategory(index: integer): TCategory;
32                 procedure SetCategory(index: integer; value: TCategory);
33                 procedure SetSelectText(s: string);
34         public
35                 constructor Create( boardFilePath : string );
36                 destructor Destroy; override;
37
38                 function Add(item: TCategory): integer;
39                 procedure Delete(index: integer);
40                 procedure Clear; override;
41                 function Find(key: string): TCategory;
42                 function FindBBSID(const BBSID: string): TBoard;
43                 function FindBoardFromTitle(const Title: string): TBoard;
44                 function FindBoardFromURL(const inURL: string): TBoard;
45                 function FindThreadFromURL(const inURL : string ) : TThreadItem;
46                 function FindThreadItem(const BBSID, FileName: string): TThreadItem;
47                 function FindCategoryFromTitle(const inTitle : string ) : TCategory;
48                 property FilePath : string read FFilePath write FFilePath;
49
50                 property Items[index: integer]: TCategory read GetCategory write SetCategory;
51                 property Title: string read FTitle write FTitle;
52                 property NodeExpand: Boolean read FExpand write FExpand;
53
54                 property KubetsuChk: Boolean read FKubetsuChk write FKubetsuChk;
55                 property SelectText: string read FSelectText write SetSelectText;
56                 property ShortSelectText: string read FShortSelectText write FShortSelectText;
57
58                 property        IsBoardFileRead : Boolean read FIsBoardFileRead write FIsBoardFileRead;
59         end;
60
61         // \83J\83e\83S\83\8a(\94 URL \82Ì\83\8a\83X\83g)
62         TCategory = class(TStringList)
63         private
64                 FNo: Integer;
65                 FTitle: string;
66                 FParenTBBS: TBBS;
67                 FExpand: Boolean;
68
69                 function GetBoard(index: integer): TBoard;
70                 procedure SetBoard(index: integer; value: TBoard);
71         public
72                 constructor Create;
73                 destructor Destroy; override;
74
75                 property No: Integer read FNo write FNo;
76                 property Title: string read FTitle write FTitle;
77                 property Items[index: integer]: TBoard read GetBoard write SetBoard;
78                 property ParenTBBS: TBBS read FParenTBBS write FParenTBBS;
79
80                 function Add(item: TBoard): integer;
81                 procedure Delete(index: integer);
82                 procedure Clear; override;
83                 function FindName(const key: string): TBoard;
84                 function FindBBSID(const BBSID: string): TBoard;
85                 function FindBoardFromTitle(const Title: string): TBoard;
86                 function FindBoardFromURL(const inURL: string): TBoard;
87                 function FindThreadFromURL(const inURL : string ) : TThreadItem;
88                 function IsMidoku: Boolean;
89
90                 property NodeExpand: Boolean read FExpand write FExpand;
91         end;
92
93         //! \83X\83\8c\83b\83h\90\94\83J\83E\83\93\83g\8fð\8c\8f\95
94         TThreadCount = function(Item : TThreadItem): Boolean;
95
96         // \94Â(\83X\83\8c\83b\83h URL \82Ì\83\8a\83X\83g)
97         TBoard = class(TStringList)
98         private
99                 FContext: DWORD;                                                        // \83v\83\89\83O\83C\83\93\82ª\8e©\97R\82É\90Ý\92è\82µ\82Ä\82¢\82¢\92l(\8eå\82É\83C\83\93\83X\83^\83\93\83X\82ª\93ü\82é)
100
101                 FNo: Integer;                                                                   //\94Ô\8d\86
102                 FTitle: string;                                                         //\83{\81[\83h\83^\83C\83g\83\8b
103                 FBBSID: string;                                                         //BBSID
104                 FURL: string;                                                                   //\83{\81[\83hURL
105                 FRound: Boolean;                                                        //\83X\83\8c\83b\83h\88ê\97\97\8f\84\89ñ\97\\96ñ
106                 FRoundName: string;                                             //\8f\84\89ñ\96¼
107                 FRoundDate: TDateTime;                          //\83X\83\8c\83b\83h\88ê\97\97\82ð\8eæ\93¾\82µ\82½\93ú\8e\9e\81i\8f\84\89ñ\93ú\8e\9e\81j
108                 FLastModified: TDateTime;                       //\83X\83\8c\83b\83h\88ê\97\97\82ª\8dX\90V\82³\82ê\82Ä\82¢\82é\93ú\8e\9e\81i\83T\81[\83o\91¤\93ú\8e\9e\81j
109                 FLastGetTime: TDateTime;                        //\83X\83\8c\83b\83h\82Ü\82½\82Í\83X\83\8c\83b\83h\88ê\97\97\82ð\8dÅ\8cã\82É\8dX\90V\82µ\82½\93ú\8e\9e\81i\83T\81[\83o\91¤\93ú\8e\9e\81E\8f\91\82«\8d\9e\82Ý\8e\9e\82É\8eg\97p\82·\82é\81j
110                 FIsThreadDatRead: Boolean;              //\83X\83\8c\83b\83h\83\8a\83X\83g\82Í\93Ç\82Ý\8d\9e\82Ü\82ê\82Ä\82¢\82é\82©\81H
111                 FUnRead: Integer;                                                       //\83X\83\8c\83b\83h\96¢\93Ç\90\94
112                 FParentCategory: TCategory;             //\90e\83J\83e\83S\83\8a
113                 FModified: Boolean;                                             //\8fC\90³\83t\83\89\83O
114                 FBoolData: Boolean;                                             //\82¢\82ë\82ñ\82È\97p\93r\82É\8eg\82¤yo
115                 FSPID: string;                                                          //\8f\91\82«\8d\9e\82Ý\97pSPID
116                 FPON: string;                                                                   //\8f\91\82«\8d\9e\82Ý\97pPON
117                 FCookie: string;                                                //\8f\91\82«\8d\9e\82Ý\97pCookie\95\8e\9a\97ñ
118                 FExpires: TDateTime;                                    //Cookie\82Ì\97L\8cø\8aú\8cÀ
119                 FKotehanName: string;                                   //\83R\83e\83n\83\93\96¼\91O
120                 FKotehanMail: string;                                   //\83R\83e\83n\83\93\83\81\81[\83\8b
121
122                 FUpdate: Boolean;
123                 FExpand: Boolean;
124
125                 FBoardPlugIn    : TBoardPlugIn; // \82±\82Ì\94Â\82ð\83T\83|\81[\83g\82·\82é\83v\83\89\83O\83C\83\93
126                 FFilePath                       : string;                               // \82±\82Ì\83X\83\8c\88ê\97\97\82ª\95Û\91\82³\82ê\82Ä\82¢\82é\83p\83X
127                 FIsLogFile              : Boolean;                      // \83\8d\83O\91\8dÝ\83t\83\89\83O
128                 FIntData                        : Integer;                      // \8dD\82«\82É\82¢\82\82Á\82Ä\82æ\82µ\81B\82¢\82ë\82ñ\82È\97p\93r\82É\8eg\82¤yo
129                 FListData                       : TList;                                // \8dD\82«\82É\82¢\82\82Á\82Ä\82æ\82µ\81B\82¢\82ë\82ñ\82È\97p\93r\82É\8eg\82¤yo
130
131                 FSETTINGTXTTime : TDateTime;    //SETTING.TXT\82ð\8eæ\93¾\82µ\82½\93ú\8e\9e
132                 FIsSETTINGTXT   : boolean;      //SETTING.TXT\82ð\8eæ\93¾\82µ\82Ä\82¢\82é\82©
133                 FHEADTXTTime    : TDateTime;            //HEAD.TXT\82ð\8eæ\93¾\82µ\82½\93ú\8e\9e
134                 FIsHEADTXT              : boolean;      //HEAD.TXT\82ð\8eæ\93¾\82µ\82Ä\82¢\82é\82©
135                 FTitlePictureURL: string;       //top\8aG\82ÌURL
136                 FMultiplicity   : Integer; //\8fd\95¡\82µ\82Ä\82¢\82é\82©\82Ç\82¤\82©\81H
137                 FIs2ch                  : Boolean; //host\82ª2ch\82©\82Ç\82¤\82©
138                 FNewThreadCount: Integer;       //\90V\92\85\83X\83\8c\83b\83h\82Ì\90\94
139                 FLogThreadCount: Integer;       //\83\8d\83O\97L\82è\83X\83\8c\83b\83h\82Ì\90\94
140                 FUserThreadCount: Integer;      //\81H
141                 FLiveThreadCount: Integer;      //\90\91\83X\83\8c\83b\83h\90\94
142                 FArchiveThreadCount: Integer;   //DAT\97\8e\82¿\83X\83\8c\83b\83h\90\94
143                 function GetThreadItem(index: integer): TThreadItem;
144                 procedure SetThreadItem(index: integer; value: TThreadItem);
145                 procedure SetRound(b: Boolean);
146                 procedure SetRoundName(s: string);
147                 //procedure SetRoundName(s: PChar);
148                 procedure SetLastModified(d: TDateTime);
149                 procedure SetLastGetTime(d: TDateTime);
150                 procedure SetUnRead(i: Integer);
151                 procedure SetKotehanName(s: string);
152                 procedure SetKotehanMail(s: string);
153                 procedure Init;
154         public
155                 constructor Create( inPlugIn : TBoardPlugIn; inURL : string );
156                 destructor Destroy; override;
157
158                 property Context: DWORD read FContext write FContext;
159
160                 property Items[index: integer]: TThreadItem read GetThreadItem write SetThreadItem;
161                 property No: Integer read FNo write FNo;
162                 property Title: string read FTitle write FTitle;
163                 property BBSID: string read FBBSID write FBBSID;
164                 property URL: string read FURL write FURL;
165                 property Round: Boolean read FRound write SetRound;
166                 //property RoundName: PChar read FRoundName write SetRoundName;
167                 property RoundName: string read FRoundName write SetRoundName;
168                 property RoundDate: TDateTime read FRoundDate write FRoundDate;
169                 property LastModified: TDateTime read FLastModified write SetLastModified;
170                 property LastGetTime: TDateTime read FLastGetTime write SetLastGetTime;
171                 property UnRead: Integer read FUnRead write SetUnRead;
172                 property Modified: Boolean read FModified write FModified;
173                 property IsThreadDatRead: Boolean read FIsThreadDatRead write FIsThreadDatRead;
174                 property ParentCategory: TCategory read FParentCategory write FParentCategory;
175
176                 property        BoardPlugIn     : TBoardPlugIn  read FBoardPlugIn;
177                 property        FilePath                : string                                read FFilePath write FFilePath;
178                 property        IsLogFile               : Boolean                               read FIsLogFile write FIsLogFile;
179                 property        IntData                 : Integer                               read FIntData write FIntData;
180                 property        ListData                : TList                                 read FListData write FListData;
181                 function        IsBoardPlugInAvailable : Boolean;
182
183                 function Add(item: TThreadItem): integer;
184                 procedure Insert(Index: Integer; Item: TThreadItem);
185                 procedure Delete(index: integer);
186                 procedure DeleteList(index: integer);
187                 procedure Clear; override;
188                 function FindThreadFromFileName(const ItemFileName: string): TThreadItem;
189                 function FindThreadFromURL(const inURL : string ) : TThreadItem;
190                 function GetIndexFromFileName(const ItemFileName: string): Integer;
191                 function GetIndexFromURL(const URL: string; reverse : Boolean = False): Integer;
192                 procedure LoadSettings;
193                 procedure SaveSettings;
194                 function GetReadCgiURL: string;
195                 function GetSubjectFileName: string;
196                 function GetFolderIndexFileName: string;
197                 function GetSETTINGTXTFileName: string;
198                 function GETHEADTXTFileName: string;
199                 function GetTitlePictureFileName: string;
200                 function GetSendURL: string;
201
202                 function GetNewThreadCount: Integer;
203                 function GetLogThreadCount: Integer;
204                 function GetArchiveThreadCount: Integer;
205                 function GetLiveThreadCount: Integer;
206                 function GetUserThreadCount: Integer;
207                 function GetNewThread(Index: Integer): TThreadItem;
208                 function GetLogThread(Index: Integer): TThreadItem; overload;
209                 function GetArchiveThread(Index: Integer): TThreadItem;
210                 function GetLiveThread(Index: Integer): TThreadItem;
211                 function GetUserThread(Index: Integer): TThreadItem;
212                 function GetThreadCount(func :TThreadCount ): Integer;
213                 function GetThread(func :TThreadCount;const Index :Integer ): TThreadItem;
214                 procedure BeginUpdate;
215                 procedure EndUpdate;
216                 property NodeExpand: Boolean read FExpand write FExpand;
217                 property BoolData: Boolean read FBoolData write FBoolData;
218                 property SPID: string read FSPID write FSPID;
219                 property PON: string read FPON write FPON;
220                 property KotehanName: string read FKotehanName write SetKotehanName;
221                 property KotehanMail: string read FKotehanMail write SetKotehanMail;
222
223                 property SETTINGTXTTime: TDateTime read FSETTINGTXTTime write FSETTINGTXTTime;
224                 property IsSETTINGTXT:  boolean read FIsSETTINGTXT write FIsSETTINGTXT;
225                 property HEADTXTTime: TDateTime read FHEADTXTTime write FHEADTXTTime;
226                 property IsHEADTXT:     boolean read FIsHEADTXT write FIsHEADTXT;
227                 property TitlePictureURL: string read FTitlePictureURL write FTitlePictureURL;
228                 property Multiplicity: Integer read FMultiplicity write FMultiplicity;
229                 property Is2ch  : boolean       read FIs2ch     write FIs2ch;
230                 property NewThreadCount: Integer        read FNewThreadCount write FNewThreadCount;     //\90V\92\85\83X\83\8c\83b\83h\82Ì\90\94
231                 property LogThreadCount: Integer        read FLogThreadCount write FLogThreadCount;             //\83\8d\83O\97L\82è\83X\83\8c\83b\83h\82Ì\90\94
232                 property UserThreadCount: Integer       read FUserThreadCount write FUserThreadCount;   //\81H
233                 property LiveThreadCount: Integer       read FLiveThreadCount write     FLiveThreadCount;
234                 property ArchiveThreadCount: Integer read FArchiveThreadCount write FArchiveThreadCount;
235
236                 property Cookie: string                         read FCookie write FCookie;
237                 property Expires: TDateTime                     read FExpires write FExpires;
238         end;
239
240         //\83X\83\8c
241         TThreadItem = class(TObject)
242         private
243                 FContext: DWORD;                                        // \83v\83\89\83O\83C\83\93\82ª\8e©\97R\82É\90Ý\92è\82µ\82Ä\82¢\82¢\92l(\8eå\82É\83C\83\93\83X\83^\83\93\83X\82ª\93ü\82é)
244                 FNo: Integer;                                                   //\94Ô\8d\86
245                 FFileName: string;                              //\83X\83\8c\83b\83h\83t\83@\83C\83\8b\96¼
246                 FTitle: string;                                         //\83X\83\8c\83b\83h\83^\83C\83g\83\8b
247                 FShortTitle: string;                    //\92Z\82¢\83X\83\8c\83b\83h\83^\83C\83g\83\8b\81i\8c\9f\8dõ\97p\81j
248                 FRoundDate: TDateTime;          //\83X\83\8c\83b\83h\82ð\8eæ\93¾\82µ\82½\93ú\8e\9e\81i\8f\84\89ñ\93ú\8e\9e\81j
249                 FLastModified: TDateTime; //\83X\83\8c\83b\83h\82ª\8dX\90V\82³\82ê\82Ä\82¢\82é\93ú\8e\9e\81i\83T\81[\83o\91¤\93ú\8e\9e\81j
250                 FCount: Integer;                                        //\83X\83\8c\83b\83h\83J\83E\83\93\83g\81i\83\8d\81[\83J\83\8b\81j
251                 FAllResCount: Integer;          //\83X\83\8c\83b\83h\83J\83E\83\93\83g\81i\83T\81[\83o\81j
252                 FNewResCount: Integer;          //\83X\83\8c\83b\83h\90V\92\85\90\94
253                 FSize: Integer;                                         //\83X\83\8c\83b\83h\83T\83C\83Y
254                 FRound: Boolean;                                        //\8f\84\89ñ\83t\83\89\83O
255                 FRoundName: string;                             //\8f\84\89ñ\96¼
256                 FIsLogFile: Boolean;                    //\83\8d\83O\91\8dÝ\83t\83\89\83O
257                 FParentBoard: TBoard;                   //\90e\83{\81[\83h
258                 FKokomade: Integer;                             //\83R\83R\82Ü\82Å\93Ç\82ñ\82¾\94Ô\8d\86
259                 FNewReceive: Integer;           //\83R\83R\82©\82ç\90V\8bK\8eó\90M
260                 FNewArrival: Boolean;                   //\90V\92\85
261                 FUnRead: Boolean;                                       //\96¢\93Ç\83t\83\89\83O
262                 FScrollTop: Integer;                    //\83X\83N\83\8d\81[\83\8b\88Ê\92u
263                 FDownloadHost: string;          //\8d¡\82Ì\83z\83X\83g\82Æ\88á\82¤\8fê\8d\87\82Ì\83z\83X\83g
264                 FAgeSage: TGikoAgeSage;         //\83A\83C\83e\83\80\82Ì\8fã\82°\89º\82°
265                 FUpdate: Boolean;
266                 FExpand: Boolean;
267                 FURL                                    : string;                               // \82±\82Ì\83X\83\8c\82ð\83u\83\89\83E\83U\82Å\95\\8e¦\82·\82é\8dÛ\82Ì URL
268                 FJumpAddress : Integer;         //\83\8c\83X\94Ô\8d\86\8ew\92èURL\82ð\93¥\82ñ\82¾\82Æ\82«\82É\8ew\92è\82³\82ê\82é\83\8c\83X\82Ì\94Ô\8d\86\82ª\93ü\82é
269                 procedure SetLastModified(d: TDateTime);
270                 procedure SetRound(b: Boolean);
271                 procedure SetRoundName(const s: string);
272                 //procedure SetRoundName(const s: PChar);
273                 procedure SetKokomade(i: Integer);
274                 procedure SetUnRead(b: Boolean);
275                 procedure SetScrollTop(i: Integer);
276                 procedure Init;
277                 function GetCreateDate: TDateTime;
278         function GetFilePath: String;
279         public
280                 constructor Create(const inPlugIn : TBoardPlugIn; const inBoard : TBoard; inURL : string ); overload;
281                 constructor Create(const inPlugIn : TBoardPlugIn; const inBoard : TBoard;
282                                          const inURL : string; inExist: Boolean; const inFilename: string ); overload;
283
284                 destructor Destroy; override;
285
286                 function GetDatURL: string;
287                 function GetDatgzURL: string;
288 //              function GetOldDatgzURL: string;
289                 function GetOfflawCgiURL(const SessionID: string): string;
290 //////////////// 2013/10/13 ShiroKuma\91Î\89\9e zako Start ///////////////////////////
291         function GetOfflaw2SoURL: string;
292 //////////////// 2013/10/13 ShiroKuma\91Î\89\9e zako End /////////////////////////////
293         function GetRokkaURL(const SessionID: string): string;  // Rokka\91Î\89\9e  
294                 function GetExternalBoardKakoDatURL: string; // \8aO\95\94\94Â\89ß\8b\8e\83\8d\83OURL\8eæ\93¾
295                 function GetSendURL: string;
296                 procedure DeleteLogFile;
297                 function GetThreadFileName: string;
298                 procedure BeginUpdate;
299                 procedure EndUpdate;
300
301                 property Context: DWORD read FContext write FContext;
302
303                 property No: Integer read FNo write FNo;
304                 property FileName: string read FFileName write FFileName;
305                 property Title: string read FTitle write FTitle;
306                 property ShortTitle: string read FShortTitle write FShortTitle;
307                 property RoundDate: TDateTime read FRoundDate write FRoundDate;
308                 property LastModified: TDateTime read FLastModified write SetLastModified;
309                 property Count: Integer read FCount write FCount;
310                 property AllResCount: Integer read FAllResCount write FAllResCount;
311                 property NewResCount: Integer read FNewResCount write FNewResCount;
312                 property Size: Integer read FSize write FSize;
313                 property Round: Boolean read FRound write SetRound;
314                 property RoundName: string read FRoundName write SetRoundName;
315                 //property RoundName: PChar read FRoundName write SetRoundName;
316
317                 property IsLogFile: Boolean read FIsLogFile write FIsLogFile;
318                 property ParentBoard: TBoard read FParentBoard write FParentBoard;
319                 property Kokomade: Integer read FKokomade write SetKokomade;
320                 property NewReceive: Integer read FNewReceive write FNewReceive;
321                 property NewArrival: Boolean read FNewArrival write FNewArrival;
322                 property UnRead: Boolean read FUnRead write SetUnRead;
323                 property ScrollTop: Integer read FScrollTop write SetScrollTop;
324                 property Expand: Boolean read FExpand write FExpand;
325                 property DownloadHost: string read FDownloadHost write FDownloadHost;
326                 property AgeSage: TGikoAgeSage read FAgeSage write FAgeSage;
327                 property CreateDate: TDateTime read GetCreateDate;
328                 property        URL                                     : string                                read FURL write FURL;
329                 property        FilePath                : string        read GetFilePath;
330                 property JumpAddress : Integer read FJumpAddress write FJumpAddress;
331         end;
332
333         TBoardGroup = class(TStringList)
334     private
335         FBoardPlugIn    : TBoardPlugIn; // \82±\82Ì\94Â\82ð\83T\83|\81[\83g\82·\82é\83v\83\89\83O\83C\83\93
336     public
337                 destructor Destroy; override;
338                 procedure       Clear   ; override;
339         property        BoardPlugIn     : TBoardPlugIn  read FBoardPlugIn write FBoardPlugIn;
340     end;
341
342     // \93Á\8eê\97p\93r\97pTBoard
343     TSpecialBoard = class(TBoard)
344     public
345         function Add(item: TThreadItem): integer; overload;
346         procedure Clear; overload;
347     end;
348
349         function        BBSsFindBoardFromBBSID( inBBSID : string ) : TBoard;
350         function        BBSsFindBoardFromURL( inURL : string ) : TBoard;
351         function        BBSsFindBoardFromTitle( inTitle : string ) : TBoard;
352         function        BBSsFindThreadFromURL(const inURL : string ) : TThreadItem;
353         function        ConvertDateTimeString( inDateTimeString : string) : TDateTime;
354
355     procedure    DestorySpecialBBS( inBBS : TBBS );
356
357 var
358         BBSs            : array of TBBS;
359     BoardGroups : array of TBoardGroup;
360     SpecialBBS  : TBBS;
361     SpecialBoard: TSpecialBoard;
362
363 implementation
364
365 uses
366         GikoSystem, RoundData, MojuUtils, DateUtils, IniFiles;
367
368 const
369         BBS2CH_NAME:                                     string = '\82Q\82¿\82á\82ñ\82Ë\82é';
370         BBS2CH_LOG_FOLDER:               string = '2ch';
371         EXTERNAL_LOG_FOLDER:            string  = 'exboard';
372
373         FOLDER_INI_FILENAME:     string = 'Folder.ini';
374         FOLDER_INDEX_FILENAME: string   = 'Folder.idx';
375         SUBJECT_FILENAME:                       string  = 'subject.txt';
376         PATH_DELIM:                                             string  = '\';
377         SETTINGTXT_FILENAME:            string = 'SETTING.TXT';
378     HEADTXT_FILENAME:           string = 'head.html';
379         //DEFAULT_LIST_COUNT:           Integer = 100;
380
381 //! \83\8d\83O\82ð\8e\9d\82Á\82Ä\82¢\82é\82È\82ç\90^\82ð\95Ô\82·
382 function CountLog(Item: TThreadItem): Boolean;
383 begin
384         Result := Item.IsLogFile;
385 end;
386 //! \90V\92\85\82È\82ç\90^\82ð\95Ô\82·
387 function CountNew(Item: TThreadItem): Boolean;
388 begin
389         Result := Item.NewArrival;
390 end;
391 //! DAT\97\8e\82¿\82È\82ç\90^\82ð\95Ô\82·
392 function CountDat(Item: TThreadItem): Boolean;
393 begin
394         Result := (Item.AgeSage = gasArch);
395 end;
396 //! \90\91\83X\83\8c\82È\82ç\90^\82ð\95Ô\82·
397 function CountLive(Item: TThreadItem): Boolean;
398 begin
399         Result := (Item.AgeSage <> gasArch);
400 end;
401
402 //! \8fí\82É\90^
403 function CountAll(Item: TThreadItem): Boolean;
404 begin
405     Result := True;
406 end;
407
408
409
410 // BBSID \82ð\97p\82¢\82é 2 \82¿\82á\82ñ\82Ë\82é\82Ì\82Ý\92T\82µ\8fo\82µ\82Ü\82·
411 // BBSID \82Ì\8eg\97p\82Í\8bÉ\97Í\94ð\82¯\82Ä\82­\82¾\82³\82¢\81B
412 // \89Â\94\\82È\8fê\8d\87\82Í URL \82ð\8eg\97p\82µ\82Ä\82­\82¾\82³\82¢\81B
413 function        BBSsFindBoardFromBBSID(
414         inBBSID : string
415 ) : TBoard;
416 var
417         i : Integer;
418         tmpBoard : TBoard;
419 begin
420
421 //      Result := BBSs[ 0 ].FindBBSID( inBBSID );
422         Result := nil;
423         if Length(BoardGroups) > 0 then begin
424                 for i := BoardGroups[0].Count - 1 downto 0 do begin
425                         tmpBoard := TBoard(BoardGroups[0].Objects[i]);
426                         if tmpBoard.Is2ch then begin
427                                 if AnsiCompareStr(tmpBoard.BBSID, inBBSID) = 0 then begin
428                                         Result := tmpBoard;
429                                         EXIT;
430                                 end;
431                         end;
432                 end;
433         end;
434
435 end;
436 {**********************************************
437 \82±\82Ì\8aÖ\90\94\82Í\95K\82¸\94Â\82ÌURL\82Ì\8c`\8e®\82Å\93n\82µ\82Ä\82­\82¾\82³\82¢\81B
438 plugin\82ð\8eg\97p\82·\82é\82È\82ç\82Î\81AExtractBoardURL( inURL )
439 2ch\82È\82ç\82Î\81AGikoSys.Get2chThreadURL2BoardURL( inURL );
440 \82Å\95Ï\8a·\82µ\82Ä\82©\82ç\8cÄ\82Ñ\8fo\82µ\82Ä\82­\82¾\82³\82¢\81B
441 **********************************************}
442 function        BBSsFindBoardFromURL(
443         inURL   : string
444 ) : TBoard;
445 var
446         i,p                     : Integer;
447         accept          : TAcceptType;
448         protocol, host, path, document, port, bookmark : string;
449 begin
450         Result := nil;
451         for i := Length(BoardGroups) - 1 downto 1 do begin
452                 accept := BoardGroups[i].BoardPlugIn.AcceptURL(inURL);
453                 if (accept = atBoard) or (accept = atThread) then begin
454                         if BoardGroups[i].Find(inURL, p) then begin
455                                 Result := TBoard(BoardGroups[i].Objects[p]);
456                                 Exit;
457                         end else begin
458                                 inURL := BoardGroups[i].BoardPlugIn.ExtractBoardURL(inURL);
459                                 if BoardGroups[i].Find(inURL, p) then begin
460                                         Result := TBoard(BoardGroups[i].Objects[p]);
461                                         Exit;
462                                 end;
463                         end;
464                 end;
465         end;
466         //\82±\82±\82É\82«\82½\82ç\81Aplugin\82ð\8eg\82í\82È\82¢\82â\82Â\82ç\82ð\92²\82×\82é
467         if BoardGroups[0].Find(inURL, p) then
468                 Result := TBoard(BoardGroups[0].Objects[p]);
469                 
470         if (Result = nil) then begin
471                 GikoSys.ParseURI( inURL, protocol, host, path, document, port, bookmark );
472                 //\83z\83X\83g\82ª2ch\82È\82çBBSID\82Å\92²\82×\82é
473                 if GikoSys.Is2chHost(host) then begin
474                         Result := BBSsFindBoardFromBBSID(GikoSys.URLToID( inURL ));
475                 end;
476         end;
477
478 end;
479
480 function        BBSsFindBoardFromTitle(
481         inTitle : string
482 ) : TBoard;
483 var
484         i,j                             : Integer;
485         tmpBoard                : TBoard;
486 begin
487     Result := nil;
488         for i := Length( BBSs ) - 1 downto 0 do begin
489                 for j := BoardGroups[i].Count - 1 downto 0 do begin
490                         tmpBoard := TBoard(BoardGroups[i].Objects[j]);
491                         if ( AnsiCompareStr(tmpBoard.Title, inTitle) = 0) then begin
492                                 Result := tmpBoard;
493                                 Exit;
494                         end;
495                 end;
496         end;
497
498 end;
499
500 function        BBSsFindThreadFromURL(
501         const inURL                     : string
502 ) : TThreadItem;
503 var
504         board                   : TBoard;
505         tmpThread               : TThreadItem;
506         boardURL        : string;
507         protocol, host, path, document, port, bookmark : string;
508         BBSID, BBSKey : string;
509         i, bi : Integer;
510 begin
511
512         boardURL        := GikoSys.GetThreadURL2BoardURL( inURL );
513         board                   := BBSsFindBoardFromURL( boardURL );
514         if board = nil then
515                 Result := nil
516         else begin
517                 Result := board.FindThreadFromURL( inURL );
518                 //\82à\82µ\82à2ch\82Ì\94Â\82È\82ç
519                 if (Result = nil) and (board.Is2ch) then begin
520                         GikoSys.ParseURI( inURL, protocol, host, path, document, port, bookmark );
521                         GikoSys.Parse2chURL( inURL, path, document, BBSID, BBSKey );
522                         Result := board.FindThreadFromFileName(BBSKey + '.dat');
523                 end else if (Result = nil) and not (board.Is2ch) then begin
524                 //\83v\83\89\83O\83C\83\93\8cn\82Ì\92T\8dõ\81i\8eå\82ÉURL\82ª\93r\92\86\82Å\95Ï\8dX\82É\82È\82Á\82½\97Þ)
525                         try
526                                 bi := Length(BoardGroups) - 1;
527                                 for i := 1 to bi do begin
528                                         if (BoardGroups[i].BoardPlugIn <> nil) and (Assigned(Pointer(BoardGroups[i].BoardPlugIn.Module))) then begin
529                                                 if BoardGroups[i].BoardPlugIn.AcceptURL( inURL ) = atThread then begin
530                                                         tmpThread               := TThreadItem.Create( BoardGroups[i].BoardPlugIn, Board, inURL );
531                                                         if not board.IsThreadDatRead then begin
532                                                                 GikoSys.ReadSubjectFile( board );
533                                                         end;
534                                                         Result := Board.FindThreadFromFileName( tmpThread.FileName );
535                                                         tmpThread.Free;
536                                                         Break;
537                                                 end;
538                                         end;
539                                 end;
540                         except
541                 Result := nil;
542                         end;
543                 end;
544         end;
545
546 end;
547 {!
548 \brief \93Á\8eê\97p\93rBBS\8dí\8f\9c
549 \param bbs \8dí\8f\9c\82·\82é\93Á\8eê\97p\93rBBS
550 }
551 procedure DestorySpecialBBS( inBBS : TBBS );
552 var
553     sCategory : TCategory;
554     sBoard    : TSpecialBoard;
555 begin
556     if inBBS <> nil then begin
557         sCategory := inBBS.Items[0];
558         if sCategory <> nil then begin
559             sBoard := TSpecialBoard(sCategory.Items[0]);
560             if sBoard <> nil then begin
561                 sBoard.Modified := False;
562                 sBoard.Clear;
563                 FreeAndNil(sBoard);
564             end;
565         end;
566         FreeAndNil(inBBS);
567     end;
568 end;
569
570 (*************************************************************************
571  *\8b@\94\\96¼\81FTBBS\83R\83\93\83X\83g\83\89\83N\83^
572  *Public
573  *************************************************************************)
574 constructor TBBS.Create( boardFilePath : string );
575 begin
576         inherited Create;
577         Title := BBS2CH_NAME;
578         FFilePath := boardFilePath;
579 end;
580
581 (*************************************************************************
582  *\8b@\94\\96¼\81FTBBS\83f\83X\83g\83\89\83N\83^
583  *Public
584  *************************************************************************)
585 destructor TBBS.Destroy;
586 begin
587         Clear;
588         inherited;
589 end;
590
591 (*************************************************************************
592  *\8b@\94\\96¼\81F
593  *Public
594  *************************************************************************)
595 function TBBS.GetCategory(index: integer): TCategory;
596 begin
597         Result := TCategory(inherited Items[index]);
598 end;
599
600 procedure TBBS.SetCategory(index: integer; value: TCategory);
601 begin
602         inherited Items[index] := value;
603 end;
604
605 function TBBS.Add(item: TCategory): integer;
606 begin
607         Item.ParenTBBS := self;
608         Result := inherited Add(item);
609 end;
610
611 procedure TBBS.Delete(index: integer);
612 begin
613         if Items[index] <> nil then
614                 TCategory(Items[index]).Free;
615         Items[index] := nil;
616         inherited Delete(index);
617 end;
618
619 procedure TBBS.Clear;
620 var
621         i: integer;
622 begin
623         for i := Count - 1 downto 0 do
624                 Delete(i);
625     Capacity := Count;
626 end;
627
628 function TBBS.Find(key: string): TCategory;
629 begin
630         Result := nil;
631 end;
632
633 function TBBS.FindBBSID(const BBSID: string): TBoard;
634 var
635         i       : Integer;
636 begin
637         if not IsBoardFileRead then
638         GikoSys.ReadBoardFile( Self );
639         for i := Count - 1 downto 0 do begin
640                 Result := Items[ i ].FindBBSID(BBSID);
641                 if Result <> nil then
642                         Exit;
643         end;
644         Result := nil;
645 end;
646
647 //*************************************************************************
648 // \83^\83C\83g\83\8b\82Ì\88ê\92v\82·\82é\94Â\82ð\92T\82·
649 //*************************************************************************)
650 function TBBS.FindBoardFromTitle(const Title: string): TBoard;
651 var
652         i: Integer;
653 begin
654         if not IsBoardFileRead then
655         GikoSys.ReadBoardFile( Self );
656         for i := Count - 1 downto 0 do begin
657                 Result := Items[ i ].FindBoardFromTitle(Title);
658                 if Result <> nil then
659                         Exit;
660         end;
661         Result := nil;
662 end;
663
664 //*************************************************************************
665 // URL \82ð\8eó\82¯\95t\82¯\82é\94Â\82ð\92T\82·
666 //*************************************************************************)
667 function TBBS.FindBoardFromURL(const inURL: string): TBoard;
668 var
669         i                                       : Integer;
670 begin
671         if not IsBoardFileRead then
672         GikoSys.ReadBoardFile( Self );
673         for i := Count - 1 downto 0 do begin
674                 Result := Items[ i ].FindBoardFromURL( inURL );
675                 if Result <> nil then
676                         Exit;
677         end;
678         Result := nil;
679 end;
680
681 //*************************************************************************
682 // URL \82ð\8eó\82¯\95t\82¯\82é\83X\83\8c\83b\83h\82ð\92T\82·
683 //*************************************************************************)
684 function TBBS.FindThreadFromURL(const inURL: string): TThreadItem;
685 var
686         board                   : TBoard;
687         boardURL        : string;
688 begin
689
690         boardURL        := GikoSys.GetThreadURL2BoardURL( inURL );
691         board                   := FindBoardFromURL( boardURL );
692         if board = nil then
693                 Result := nil
694         else
695                 Result := board.FindThreadFromURL( inURL );
696
697 end;
698
699 function TBBS.FindThreadItem(const BBSID, FileName: string): TThreadItem;
700 var
701         Board: TBoard;
702 begin
703         Result := nil;
704         Board := FindBBSID(BBSID);
705         if Board = nil then
706                 Exit;
707         Result := Board.FindThreadFromFileName(FileName);
708 end;
709
710 function TBBS.FindCategoryFromTitle(const inTitle : string ) : TCategory;
711 var
712         i : Integer;
713 begin
714
715         for i := Count - 1 downto 0 do begin
716                 if AnsiCompareStr(Items[ i ].Title, inTitle) = 0 then begin
717                         Result := Items[ i ];
718                         Exit;
719                 end;
720         end;
721
722         Result := nil;
723
724 end;
725
726 procedure TBBS.SetSelectText(s: string);
727 begin
728         FSelectText := s;
729         ShortSelectText := CustomStringReplace(ZenToHan(s), ' ', '');
730 end;
731
732 {class function TBBS.GetColumnName(Index: Integer): string;
733 begin
734         Result := COLUMN_CATEGORY[Index];
735 end;
736
737 class function TBBS.GetColumnCount: Integer;
738 begin
739         Result := Length(COLUMN_CATEGORY);
740 end;}
741
742 //===================
743 //TCategory
744 //===================
745 constructor TCategory.Create;
746 begin
747         inherited;
748
749         Duplicates              := dupIgnore;
750         CaseSensitive   := False;
751         //Sorted                                := True;
752 end;
753
754 destructor TCategory.Destroy;
755 begin
756         Clear;
757         inherited;
758 end;
759
760 function TCategory.GetBoard(index: integer): TBoard;
761 begin
762         Result := TBoard( Objects[index] );
763 end;
764
765 procedure TCategory.SetBoard(index: integer; value: TBoard);
766 begin
767         Objects[index] := value;
768         Strings[index] := value.URL
769 end;
770
771 function TCategory.Add(item: TBoard): integer;
772 begin
773         Item.ParentCategory := self;
774         Result := AddObject( item.URL, item );
775 end;
776
777 procedure TCategory.Delete(index: integer);
778 begin
779     inherited Delete(index);
780 end;
781
782 procedure TCategory.Clear;
783 var
784         i: integer;
785 begin
786         for i := Count - 1 downto 0 do
787                 Delete(i);
788         Capacity := Count;
789 end;
790
791 function TCategory.FindName(const key: string): TBoard;
792 begin
793         Result := nil;
794 end;
795
796 function TCategory.FindBBSID(const BBSID: string): TBoard;
797 var
798         i       : integer;
799 begin
800         for i := Count - 1 downto 0 do begin
801                 if AnsiCompareStr(Items[i].FBBSID, BBSID) = 0 then begin
802                         Result := Items[i];
803                         Exit;
804                 end;
805         end;
806         Result := nil;
807 end;
808
809 //*************************************************************************
810 // \83^\83C\83g\83\8b\82Ì\88ê\92v\82·\82é\94Â\82ð\92T\82·
811 //*************************************************************************)
812 function TCategory.FindBoardFromTitle(const Title: string): TBoard;
813 var
814         i       : integer;
815 begin
816         for i := Count - 1 downto 0 do begin
817                 if AnsiCompareStr(Items[i].FTitle, Title) = 0 then begin
818                         Result := Items[i];
819                         Exit;
820                 end;
821         end;
822         Result := nil;
823 end;
824
825 //*************************************************************************
826 // URL \82ð\8eó\82¯\95t\82¯\82é\94Â\82ð\92T\82·
827 //*************************************************************************)
828 function TCategory.FindBoardFromURL(const inURL: string): TBoard;
829 var
830         i       : Integer;
831 begin
832         i := IndexOf( inURL );
833         if i >= 0 then
834                 Result := TBoard( Objects[ i ] )
835         else
836                 Result := nil;
837 end;
838
839 //*************************************************************************
840 // URL \82ð\8eó\82¯\95t\82¯\82é\83X\83\8c\83b\83h\82ð\92T\82·
841 //*************************************************************************)
842 function TCategory.FindThreadFromURL(const inURL: string): TThreadItem;
843 var
844         board                   : TBoard;
845         boardURL        : string;
846 begin
847
848         boardURL        := GikoSys.GetThreadURL2BoardURL( inURL );
849         board                   := FindBoardFromURL( boardURL );
850         if board = nil then
851                 Result := nil
852         else
853                 Result := board.FindThreadFromURL( inURL );
854
855 end;
856
857 function TCategory.IsMidoku: Boolean;
858 var
859         i: Integer;
860         j: Integer;
861 begin
862         Result := False;
863         for i := 0 to Count - 1 do begin
864                 if Items[i] <> nil then begin
865                         for j := 0 to Items[i].Count - 1 do begin
866                                 if Items[i].Items[j] <> nil then begin
867 //                                      if (Items[i].Items[j].IsLogFile) and (Items[i].Items[j].Count > Items[i].Items[j].Kokomade) then begin
868                                         if (Items[i].Items[j].IsLogFile) and (Items[i].Items[j].UnRead) then begin
869                                                 Result := True;
870                                                 Exit;
871                                         end;
872                                 end;
873                         end;
874                 end;
875         end;
876 end;
877
878 {class function TCategory.GetColumnName(Index: Integer): string;
879 begin
880         Result := COLUMN_BOARD[Index];
881 end;
882
883 class function TCategory.GetColumnCount: Integer;
884 begin
885         Result := Length(COLUMN_BOARD);
886 end;}
887
888 //===================
889 //TBoard
890 //===================
891 procedure TBoard.Init;
892 begin
893         Duplicates              := dupIgnore;
894         CaseSensitive   := False;
895         //Sorted                                := True;
896
897         FNo := 0;
898         FTitle := '';
899         FBBSID := '';
900         FURL := '';
901         FRound := False;
902         FRoundDate := ZERO_DATE;
903         FLastModified := ZERO_DATE;
904         FLastGetTime := ZERO_DATE;
905         FIsThreadDatRead := False;
906         FUnRead := 0;
907         FMultiplicity := 0;
908 //      FListStyle := vsReport;
909 //      FItemNoVisible := True;
910
911         FUpdate := True;
912 end;
913
914 // *************************************************************************
915 // \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ð\8ew\92è\82µ\82½\83R\83\93\83X\83g\83\89\83N\83^
916 // *************************************************************************
917 constructor TBoard.Create(
918         inPlugIn        : TBoardPlugIn;
919         inURL                   : string
920 );
921 var
922         protocol, host, path, document, port, bookmark  : string;
923 begin
924
925         inherited Create;
926         Init;
927
928         FBoardPlugIn    := inPlugIn;
929         URL                                             := inURL;
930         BBSID                                   := GikoSys.UrlToID( inURL );
931
932         if inPlugIn = nil then begin
933                 // subject.txt \82Ì\95Û\91\83p\83X\82ð\90Ý\92è
934                 GikoSys.ParseURI( inURL, protocol, host, path, document, port, bookmark );
935                 if GikoSys.Is2chHost( host ) then begin
936                         Self.Is2ch := True;
937                         FilePath :=
938                                 GikoSys.Setting.LogFolderP  +
939                                 BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + SUBJECT_FILENAME
940                 end else begin
941                         Self.Is2ch := False;
942                         FilePath :=
943                                 GikoSys.Setting.LogFolderP +
944                                 EXTERNAL_LOG_FOLDER + PATH_DELIM + host + PATH_DELIM + BBSID + PATH_DELIM + SUBJECT_FILENAME
945                 end;
946         end else begin
947                 // \83v\83\89\83O\83C\83\93\82É TBoardItem \82ª\8dì\90¬\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
948                 inPlugIn.CreateBoardItem( DWORD( Self ) );
949                 //Self.Is2ch := False;  //plugin\91¤\82Å\90Ý\92è\82·\82é
950         end;
951
952 end;
953
954 // *************************************************************************
955 // \83f\83X\83g\83\89\83N\83^
956 // *************************************************************************
957 destructor TBoard.Destroy;
958 begin
959         if FModified then begin
960                 GikoSys.WriteThreadDat(Self);
961                 SaveSettings;
962         end;
963
964         // \83v\83\89\83O\83C\83\93\82É TBoardItem \82ª\94j\8aü\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
965         if IsBoardPlugInAvailable then
966                 BoardPlugIn.DisposeBoardItem( DWORD( Self ) );
967
968         Clear;
969         inherited;
970 end;
971
972 // *************************************************************************
973 // \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ª\8eg\97p\89Â\94\\82©
974 // *************************************************************************
975 function        TBoard.IsBoardPlugInAvailable : Boolean;
976 begin
977
978         repeat
979                 if BoardPlugIn = nil then
980                         Break;
981                         
982                 if not Assigned( Pointer( BoardPlugIn.Module ) ) then
983                         Break;
984
985                 Result := True;
986                 Exit;
987         until True;
988
989         Result := False;
990
991 end;
992
993 function TBoard.GetThreadItem(index: integer): TThreadItem;
994 begin
995         Result := TThreadItem( Objects[index] );
996 end;
997
998 procedure TBoard.SetThreadItem(index: integer; value: TThreadItem);
999 begin
1000         Objects[index] := value;
1001         Strings[index] := value.URL;
1002 end;
1003
1004 function TBoard.Add(Item: TThreadItem): Integer;
1005 begin
1006         Item.ParentBoard := Self;
1007         Result := inherited AddObject(Item.URL, Item);
1008 end;
1009
1010 procedure TBoard.Insert(Index: Integer; Item: TThreadItem);
1011 begin
1012         Item.ParentBoard := Self;
1013         inherited InsertObject(Index, Item.URL, Item);
1014
1015 end;
1016
1017 //Index\82Å\8ew\92è\82³\82ê\82½\83X\83\8c\83b\83h\83I\83u\83W\83F\83N\83g\82ð\94j\8aü
1018 procedure TBoard.Delete(index: Integer);
1019 begin
1020         if Items[index] <> nil then
1021                 TThreadItem(Items[index]).Free;
1022         inherited Delete(index);
1023 end;
1024
1025 //Index\82Å\8ew\92è\82³\82ê\82½\83X\83\8c\83b\83h\82ð\83\8a\83X\83g\82©\82ç\8dí\8f\9c\81i\83X\83\8c\83I\83u\83W\83F\83N\83g\82Í\82Ì\82±\82·\81j
1026 procedure TBoard.DeleteList(index: integer);
1027 begin
1028         inherited Delete(index);
1029 end;
1030
1031 procedure TBoard.Clear;
1032 var
1033         i: integer;
1034 begin
1035 //      FUnRead := 0;
1036         for i := Count - 1 downto 0 do
1037                 Delete(i);
1038          Capacity := Count;
1039 end;
1040
1041 function TBoard.FindThreadFromFileName(const ItemFileName: string): TThreadItem;
1042 var
1043         i: integer;
1044 begin
1045         Result := nil;
1046         for i := 0 to Count - 1 do begin
1047                 if AnsiCompareStr(Items[i].FileName, ItemFileName) = 0 then begin
1048                         Result := Items[i];
1049                         Exit;
1050                 end;
1051         end;
1052 end;
1053
1054 function TBoard.GetIndexFromFileName(const ItemFileName: string): Integer;
1055 var
1056         i: integer;
1057 begin
1058         Result := -1;
1059         for i := 0 to Count - 1 do begin
1060                 if Items[i].FileName = ItemFileName then begin
1061                         Result := i;
1062                         Exit;
1063                 end;
1064         end;
1065 end;
1066
1067 function TBoard.GetIndexFromURL(const URL: string; reverse : Boolean = False): Integer;
1068 var
1069         i : Integer;
1070 begin
1071         if not reverse then
1072                 Result := IndexOf( URL )
1073         else begin
1074         Result := -1;
1075                 for i := Self.Count - 1 downto 0 do begin
1076                         if Strings[i] = URL then begin
1077                                 Result := i;
1078                                 break;
1079                         end;
1080                 end;
1081         end;
1082 end;
1083
1084 function TBoard.FindThreadFromURL(const inURL : string ) : TThreadItem;
1085 var
1086         i : Integer;
1087 begin
1088
1089         if not IsThreadDatRead then
1090                 GikoSys.ReadSubjectFile( Self );
1091
1092         i := IndexOf( inURL );
1093         if i >= 0 then
1094                 Result := TThreadItem( Objects[ i ] )
1095         else
1096                 Result := nil;
1097
1098 end;
1099
1100 {function TBoard.GetMidokuCount: Integer;
1101 var
1102         i: integer;
1103 begin
1104         Result := 0;
1105         for i := 0 to Count- 1 do begin
1106                 if Items[i] <> nil then begin
1107                         if (Items[i].IsLogFile) and (Items[i].Count > Items[i].Kokomade) then
1108                                 inc(Result);
1109                 end;
1110         end;
1111 end;
1112 }
1113
1114 procedure TBoard.LoadSettings;
1115 var
1116         ini: TMemIniFile;
1117         FileName: string;
1118         tmp: string;
1119 begin
1120         if Length( FilePath ) > 0 then
1121                 FileName := ExtractFilePath( FilePath ) + FOLDER_INI_FILENAME
1122         else
1123                 FileName := GikoSys.Setting.LogFolderP
1124                                                         + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + FOLDER_INI_FILENAME;
1125
1126         if not FileExists(FileName) then
1127                 Exit;
1128         ini := TMemIniFile.Create(FileName);
1129         try
1130 //              Round := ini.ReadBool('Status', 'Round', False);
1131                 tmp := ini.ReadString('Status', 'RoundDate', DateTimeToStr(ZERO_DATE));
1132                 FRoundDate := ConvertDateTimeString(tmp);
1133                 tmp := ini.ReadString('Status', 'LastModified', DateTimeToStr(ZERO_DATE));
1134                 FLastModified := ConvertDateTimeString(tmp);
1135                 tmp := ini.ReadString('Status', 'LastGetTime', DateTimeToStr(ZERO_DATE));
1136                 FLastGetTime := ConvertDateTimeString(tmp);
1137
1138                 tmp := ini.ReadString('BoardInformation', 'SETTINGTXTTime', DateTimeToStr(ZERO_DATE));
1139                 FSETTINGTXTTime := ConvertDateTimeString(tmp);
1140                 tmp := ini.ReadString('BoardInformation', 'HEADTXTTime', DateTimeToStr(ZERO_DATE));
1141                 FHEADTXTTime := ConvertDateTimeString(tmp);
1142
1143                 FIsSETTINGTXT := ini.ReadBool('BoardInformation', 'IsSETTINGTXT', false);
1144                 FIsHEADTXT := ini.ReadBool('BoardInformation', 'IsHEADTXT', false);
1145                 FTitlePictureURL := ini.ReadString('BoardInformation', 'TitlePictureURL', '');
1146
1147                 FUnRead := ini.ReadInteger('Status', 'UnRead', 0);
1148                 FSPID := ini.ReadString('Cookie', 'SPID', '');
1149                 FPON := ini.ReadString('Cookie', 'PON', '');
1150                 FCookie  := ini.ReadString('Cookie', 'Cookie', '');
1151                 tmp := ini.ReadString('Cookie', 'Expires', DateTimeToStr(ZERO_DATE));
1152                 FExpires := ConvertDateTimeString(tmp);
1153                 FKotehanName := ini.ReadString('Kotehan', 'Name', '');
1154                 FKotehanMail := ini.ReadString('Kotehan', 'Mail', '');
1155
1156                 if UnRead < 0 then
1157                         UnRead := 0;
1158         finally
1159                 ini.Free;
1160         end;
1161 end;
1162
1163 procedure TBoard.SaveSettings;
1164 var
1165         ini: TMemIniFile;
1166         FileName: string;
1167 begin
1168         if Length( FilePath ) > 0 then
1169                 FileName := ExtractFilePath( FilePath )
1170         else
1171                 FileName := GikoSys.Setting.LogFolderP
1172                                                         + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM;
1173         if not GikoSys.DirectoryExistsEx(FileName) then
1174                 GikoSys.ForceDirectoriesEx(FileName);
1175         FileName := FileName + FOLDER_INI_FILENAME;
1176         ini := TMemIniFile.Create(FileName);
1177         try
1178                 if UnRead < 0 then
1179                         UnRead := 0;
1180 //              ini.WriteBool('Status', 'Round', Round);
1181                 ini.WriteDateTime('Status', 'RoundDate', FRoundDate);
1182                 ini.WriteDateTime('Status', 'LastModified', FLastModified);
1183                 ini.WriteDateTime('Status', 'LastGetTime', FLastGetTime);
1184                 ini.WriteInteger('Status', 'UnRead', FUnRead);
1185                 ini.WriteString('Cookie', 'SPID', FSPID);
1186                 ini.WriteString('Cookie', 'PON', FPON);
1187                 ini.WriteString('Cookie', 'Cookie', FCookie);
1188                 ini.WriteDateTime('Cookie', 'Expires', FExpires);
1189                 ini.WriteString('Kotehan', 'Name', FKotehanName);
1190                 ini.WriteString('Kotehan', 'Mail', FKotehanMail);
1191
1192                 ini.WriteDateTime('BoardInformation', 'SETTINGTXTTime', FSETTINGTXTTime);
1193                 ini.WriteDateTime('BoardInformation', 'HEADTXTTime', FHEADTXTTime);
1194
1195                 ini.WriteBool('BoardInformation', 'IsSETTINGTXT', FIsSETTINGTXT);
1196                 ini.WriteBool('BoardInformation', 'IsHEADTXT', FIsHEADTXT);
1197                 ini.WriteString('BoardInformation', 'TitlePictureURL', FTitlePictureURL);
1198 //              ini.WriteInteger('Status', 'ListStyle', Ord(ListStyle));
1199 //              ini.WriteBool('Status', 'ItemNoVisible', ItemNoVisible);
1200 //              ini.WriteInteger('Status', 'ViewType', Ord(ViewType));
1201                 ini.UpdateFile;
1202         finally
1203                 ini.Free;
1204         end;
1205 end;
1206 //\82Æ\82«\82½\82Ü2003 02 08 0:32:13\82±\82ñ\82È\8c`\8e®\82Ì\93ú\95t\82ª\82 \82é\82Ì\82Å\82»\82ê\82ð
1207 //        2003/02/08 0:32:13\82É\95Ï\8a·\82·\82é
1208 function        ConvertDateTimeString( inDateTimeString : string) : TDateTime;
1209 const
1210         ZERO_DATE_STRING : string = '1970/01/01 0:00:00';
1211 var
1212         i : Integer;
1213     y: Integer;
1214     m: Integer;
1215     d: Integer;
1216     hour: Integer;
1217     min: Integer;
1218     sec: Integer;
1219 begin
1220     if inDateTimeString = '' then
1221         inDateTimeString := ZERO_DATE_STRING;
1222
1223     if ( AnsiPos('/', inDateTimeString ) = 0 ) and
1224         ( AnsiCompareStr( DateTimeToStr(ZERO_DATE), inDateTimeString) <> 0 ) then begin
1225                 for i := 0 to 1 do begin
1226                 Insert('/',inDateTimeString, AnsiPos(' ', inDateTimeString) + 1 );
1227                 Delete(inDateTimeString, AnsiPos(' ', inDateTimeString), 1);
1228         end;
1229     end;
1230     try
1231         Result := StrToDateTime( inDateTimeString );
1232     except
1233         if( inDateTimeString[5] = '/' ) and ( inDateTimeString[8] = '/' ) then begin
1234             y := StrToIntDef( Copy(inDateTimeString, 1, 4), 1970 );
1235                         m := StrToIntDef( Copy(inDateTimeString, 6, 2), 1 );
1236             d := StrToIntDef( Copy(inDateTimeString, 9, 2), 1 );
1237             hour := 0; min  := 0; sec  := 0;
1238
1239                 if Length(inDateTimeString) > 11 then begin
1240                 if( inDateTimeString[13] = ':' ) and ( inDateTimeString[16] = ':' ) then begin
1241                         hour := StrToIntDef( Copy(inDateTimeString, 12, 1), 0 );
1242                     min  := StrToIntDef( Copy(inDateTimeString, 14, 2), 0 );
1243                     sec  := StrToIntDef( Copy(inDateTimeString, 17, 2), 0 );
1244                 end else if( inDateTimeString[14] = ':' ) and ( inDateTimeString[17] = ':' ) then begin
1245                         hour := StrToIntDef( Copy(inDateTimeString, 12, 2), 0 );
1246                     min  := StrToIntDef( Copy(inDateTimeString, 15, 2), 0 );
1247                     sec  := StrToIntDef( Copy(inDateTimeString, 18, 2), 0 );
1248                 end;
1249             end;
1250             try
1251                 Result := EncodeDateTime(y ,m, d, hour, min, sec, 0);
1252             except
1253                 Result := ZERO_DATE;
1254             end;
1255         end else
1256                 Result := ZERO_DATE;
1257     end;
1258
1259
1260    // Result := inDateTimeString;
1261 end;
1262 //! \83T\83u\83W\83F\83N\83gURL\8eæ\93¾
1263 function TBoard.GetReadCgiURL: string;
1264 begin
1265         Result := URL + SUBJECT_FILENAME;
1266
1267 end;
1268
1269 //! \83T\83u\83W\83F\83N\83g\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
1270 function TBoard.GetSubjectFileName: string;
1271 begin
1272         if Length( FilePath ) > 0 then
1273                 Result := FilePath
1274         else
1275                 Result := GikoSys.Setting.LogFolderP
1276                                                 + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + SUBJECT_FILENAME;
1277 end;
1278
1279 //! \83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b\96¼(folder.idx)\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
1280 function TBoard.GetFolderIndexFileName: string;
1281 begin
1282         if Length( FilePath ) > 0 then
1283                 Result := ExtractFilePath( FilePath ) + FOLDER_INDEX_FILENAME
1284         else
1285                 Result := GikoSys.Setting.LogFolderP
1286                                                 + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + FOLDER_INDEX_FILENAME;
1287 end;
1288 //! SETTING.TXT\82Ì\83t\83@\83C\83\8b\96¼\8eæ\93¾
1289 function TBoard.GetSETTINGTXTFileName: string;
1290 begin
1291         if Length( FilePath ) > 0 then
1292                 Result := ExtractFilePath( FilePath ) + SETTINGTXT_FILENAME
1293         else
1294                 Result := GikoSys.Setting.LogFolderP
1295                                                 + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + SETTINGTXT_FILENAME;
1296 end;
1297
1298 function TBoard.GETHEADTXTFileName: string;
1299 begin
1300         if Length( FilePath ) > 0 then
1301                 Result := ExtractFilePath( FilePath ) + HEADTXT_FILENAME
1302         else
1303                 Result := GikoSys.Setting.LogFolderP
1304                                                 + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + HEADTXT_FILENAME;
1305 end;
1306 function TBoard.GetTitlePictureFileName: string;
1307 var
1308         tmpName: string;
1309 begin
1310         if FTitlePictureURL = '' then
1311                 Result := ''
1312         else begin
1313                 tmpName := Copy(FTitlePictureURL, LastDelimiter('/', FTitlePictureURL) + 1, Length(FTitlePictureURL));
1314                 if Length( FilePath ) > 0 then
1315                         Result := ExtractFilePath( FilePath ) + tmpName
1316                 else
1317                         Result := GikoSys.Setting.LogFolderP
1318                                                         + BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + tmpName;
1319         end;
1320 end;
1321
1322 // \83X\83\8c\97§\82Ä\91\97\90MURL
1323 function TBoard.GetSendURL: string;
1324 begin
1325     Result := GikoSys.UrlToServer(URL);
1326         if Self.Is2ch then
1327         Result := Result + 'test/bbs.cgi'
1328     else
1329         Result := Result + 'test/subbbs.cgi';
1330
1331 end;
1332
1333 procedure TBoard.SetRound(b: Boolean);
1334 begin
1335         if b then
1336                 RoundList.Add(Self)
1337         else
1338                 RoundList.Delete(Self);
1339         if FRound = b then Exit;
1340         FRound := b;
1341         if FUpdate then
1342                 FModified := True;
1343 end;
1344
1345 procedure TBoard.SetRoundName(s: string);
1346 begin
1347         if FRoundName = s then Exit;
1348         FRoundName := s;
1349         if FUpdate then
1350                 FModified := True;
1351 end;
1352
1353 procedure TBoard.SetLastModified(d: TDateTime);
1354 begin
1355         if FLastModified = d then Exit;
1356         FLastModified := d;
1357         if FUpdate then
1358                 FModified := True;
1359 end;
1360
1361 procedure TBoard.SetLastGetTime(d: TDateTime);
1362 begin
1363         if FLastGetTime = d then Exit;
1364         FLastGetTime := d;
1365         if FUpdate then
1366                 FModified := True;
1367 end;
1368
1369 procedure TBoard.SetUnRead(i: Integer);
1370 begin
1371         if FUnRead = i then Exit;
1372         if i < 0 then i := 0;
1373         FUnRead := i;
1374         if FUpdate then
1375                 FModified := True;
1376 end;
1377
1378 procedure TBoard.SetKotehanName(s: string);
1379 begin
1380         if FKotehanName = s then Exit;
1381         FKotehanName := s;
1382         if FUpdate then
1383                 FModified := True;
1384 end;
1385
1386 procedure TBoard.SetKotehanMail(s: string);
1387 begin
1388         if FKotehanMail = s then Exit;
1389         FKotehanMail := s;
1390         if FUpdate then
1391                 FModified := True;
1392 end;
1393 //! func\82Ì\8fð\8c\8f\82É\88ê\92v\82·\82é\83X\83\8c\83b\83h\82Ì\90\94\82ð\95Ô\82·
1394 function TBoard.GetThreadCount(func :TThreadCount ): Integer;
1395 var
1396         i: Integer;
1397 begin
1398         Result := 0;
1399         if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
1400         begin
1401                 for i := 0 to Count - 1 do begin
1402                         if func(Items[i]) then
1403                                 inc(Result);
1404                 end;
1405         end else begin
1406                 for i := 0 to Count - 1 do begin
1407                         if func(Items[i]) then
1408                         begin
1409                                 if Items[i].ShortTitle = '' then
1410                                         Items[i].ShortTitle := CustomStringReplace(ZenToHan(Items[i].Title), ' ', '');
1411                                 if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then
1412                                         inc(Result);
1413                         end;
1414                 end;
1415         end;
1416 end;
1417 //! \90V\92\85\83X\83\8c\83b\83h\82Ì\90\94\82ð\8eæ\93¾\82·\82é
1418 function TBoard.GetNewThreadCount: Integer;
1419 begin
1420         Result := GetThreadCount(CountNew);
1421 end;
1422 //! \83\8d\83O\97L\82è\83X\83\8c\83b\83h\82Ì\90\94\82ð\8eæ\93¾\82·\82é
1423 function TBoard.GetLogThreadCount: Integer;
1424 begin
1425         Result := GetThreadCount(CountLog);
1426 end;
1427 //! \8di\8d\9e\82Ý\8fð\8c\8f\82É\88ê\92v\82·\82é\83X\83\8c\83b\83h\82Ì\90\94\82ð\8eæ\93¾\82·\82é
1428 function TBoard.GetUserThreadCount: Integer;
1429 begin
1430         Result := GetThreadCount(CountAll);
1431 end;
1432 //! DAT\97\8e\82¿\83X\83\8c\83b\83h\82Ì\90\94\82ð\8eæ\93¾\82·\82é
1433 function TBoard.GetArchiveThreadCount: Integer;
1434 begin
1435         Result := GetThreadCount(CountDat);
1436 end;
1437 //! \90\91\83X\83\8c\83b\83h\82Ì\90\94\82ð\8eæ\93¾\82·\82é
1438 function TBoard.GetLiveThreadCount: Integer;
1439 begin
1440         Result := GetThreadCount(CountLive);
1441 end;
1442 //! func\82Ì\8fð\8c\8f\82É\93K\8d\87\82·\82éIndex\94Ô\96Ú\82Ì\83X\83\8c\83b\83h\82ð\8eæ\93¾\82·\82é
1443 function TBoard.GetThread(func :TThreadCount;const Index :Integer ): TThreadItem;
1444 var
1445         i: Integer;
1446         Cnt: Integer;
1447 begin
1448         Result := nil;
1449         Cnt := 0;
1450         if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
1451         begin
1452                 for i := 0 to Count - 1 do begin
1453                         if func(Items[i]) then begin
1454                                 if Index = Cnt then begin
1455                                         Result := Items[i];
1456                                         Exit;
1457                                 end;
1458                                 inc(Cnt);
1459                         end;
1460                 end;
1461         end else begin
1462                 for i := 0 to Count - 1 do begin
1463                         if func(Items[i]) then begin
1464                                 if Length(Items[i].ShortTitle) = 0 then
1465                                         Items[i].ShortTitle := CustomStringReplace(ZenToHan(Items[i].Title), ' ', '');
1466                                 if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
1467                                         if Index = Cnt then begin
1468                                                 Result := Items[i];
1469                                                 Exit;
1470                                         end;
1471                                         inc(Cnt);
1472                                 end;
1473                         end;
1474                 end;
1475         end;
1476 end;
1477 //! DAT\97\8e\82¿\83X\83\8c\83b\83h\82ÅIndex\94Ô\96Ú\82Ì\83X\83\8c\83b\83h\82ð\8eæ\93¾\82·\82é
1478 function TBoard.GetArchiveThread(Index: Integer): TThreadItem;
1479 begin
1480         Result := GetThread(CountDat, Index);
1481 end;
1482 //! \90\91\83X\83\8c\83b\83h\82ÅIndex\94Ô\96Ú\82Ì\83X\83\8c\83b\83h\82ð\8eæ\93¾\82·\82é
1483 function TBoard.GetLiveThread(Index: Integer): TThreadItem;
1484 begin
1485         Result := GetThread(CountLive, Index);
1486 end;
1487 //! \90V\92\85\83X\83\8c\83b\83h\82ÅIndex\94Ô\96Ú\82Ì\83X\83\8c\83b\83h\82ð\8eæ\93¾\82·\82é
1488 function TBoard.GetNewThread(Index: Integer): TThreadItem;
1489 begin
1490         Result := GetThread(CountNew, Index);
1491 end;
1492 //! Log\82 \82è\83X\83\8c\83b\83h\82ÌIndex\94Ô\96Ú\82Ì\83X\83\8c\83b\83h\82ð\8eæ\93¾\82·\82é
1493 function TBoard.GetLogThread(Index: Integer): TThreadItem;
1494 begin
1495         Result := GetThread(CountLog, Index);
1496 end;
1497 //! \8di\8d\9e\82Ý\82ÅIndex\94Ô\96Ú\82Ì\83X\83\8c\83b\83h\82ð\8eæ\93¾\82·\82é
1498 function TBoard.GetUserThread(Index: Integer): TThreadItem;
1499 begin
1500         Result := GetThread(CountAll, Index);
1501 end;
1502
1503 procedure TBoard.BeginUpdate;
1504 begin
1505         FUpdate := False;
1506 end;
1507
1508 procedure TBoard.EndUpdate;
1509 begin
1510         FUpdate := True;
1511 end;
1512
1513 //constructor TThreadItem.Create(AOwner: TComponent);
1514 procedure TThreadItem.Init;
1515 begin
1516         FNo := 0;
1517         FFileName := '';
1518         FTitle := '';
1519         FRoundDate := ZERO_DATE;
1520         FLastModified := ZERO_DATE;
1521         FCount := 0;
1522         FAllResCount := 0;
1523         FNewResCount := 0;
1524         FSize := 0;
1525         FRound := False;
1526         FIsLogFile := False;
1527         FParentBoard := nil;
1528         FKokomade := -1;
1529         FNewReceive := 0;
1530         FNewArrival := False;
1531
1532         FUpdate := True;
1533         FURL := '';
1534         FJumpAddress := 0;
1535 end;
1536
1537 // *************************************************************************
1538 // \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ð\8ew\92è\82µ\82½\83R\83\93\83X\83g\83\89\83N\83^
1539 // *************************************************************************
1540 constructor TThreadItem.Create(
1541         const inPlugIn : TBoardPlugIn;
1542         const inBoard : TBoard;
1543         inURL : string
1544 );
1545 var
1546         foundPos                        : Integer;
1547         protocol, host, path, document, port, bookmark  : string;
1548         BBSID, BBSKey   : string;
1549 const
1550         READ_PATH                                                       = '/test/read.cgi';
1551 begin
1552
1553         inherited Create;
1554         Init;
1555         FParentBoard    := inBoard;
1556         //FBoardPlugIn  := inPlugIn;
1557         URL                             := inURL;
1558
1559         if inPlugIn = nil then begin
1560                 foundPos := Pos( READ_PATH, inURL );
1561                 if foundPos > 0 then begin
1562                         // dat \82Ì\95Û\91\83p\83X\82ð\90Ý\92è
1563                         GikoSys.ParseURI( inURL, protocol, host, path, document, port, bookmark );
1564                         GikoSys.Parse2chURL( inURL, path, document, BBSID, BBSKey );
1565                         FileName        := BBSKey + '.dat';
1566                         IsLogFile       := FileExists( FilePath );
1567                         URL                             := GikoSys.Get2chBrowsableThreadURL( inURL );
1568                 end;
1569         end else begin
1570                 // \83v\83\89\83O\83C\83\93\82É TThreadItem \82ª\8dì\90¬\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
1571                 inPlugIn.CreateThreadItem( DWORD( Self ) );
1572         end;
1573
1574 end;
1575 // *************************************************************************
1576 // \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ð\8ew\92è\82µ\82½\83R\83\93\83X\83g\83\89\83N\83^ Log\97L\82è\82©\82Ç\82¤\82©\94»\92f\8dÏ\82Ý
1577 // FileName\82à\8eæ\93¾\8dÏ\82Ý\81@\81¨\81@ReadSubject\97p
1578 // *************************************************************************
1579 constructor TThreadItem.Create(
1580         const inPlugIn : TBoardPlugIn;
1581         const inBoard : TBoard;
1582         const inURL : string;
1583         inExist: Boolean;
1584         const inFilename: string
1585 );
1586 begin
1587
1588         inherited Create;
1589         Init;
1590         FParentBoard    := inBoard;
1591         URL                             := inURL;
1592
1593         if inPlugIn = nil then begin
1594                 // dat \82Ì\95Û\91\83p\83X\82ð\90Ý\92è
1595                 FileName        := inFilename;
1596                 IsLogFile       := inExist;
1597         URL                             := inURL;
1598         end else begin
1599                 // \83v\83\89\83O\83C\83\93\82É TThreadItem \82ª\8dì\90¬\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
1600                 inPlugIn.CreateThreadItem( DWORD( Self ) );
1601         end;
1602
1603 end;
1604 // *************************************************************************
1605 // \83f\83X\83g\83\89\83N\83^
1606 // *************************************************************************
1607 destructor TThreadItem.Destroy;
1608 begin
1609
1610         // \83v\83\89\83O\83C\83\93\82É TThreadItem \82ª\94j\8aü\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
1611         if Self.ParentBoard.IsBoardPlugInAvailable then
1612                 Self.ParentBoard.BoardPlugIn.DisposeThreadItem( DWORD( Self ) );
1613
1614         inherited;
1615
1616 end;
1617
1618 function TThreadItem.GetDatURL: string;
1619 var
1620         Protocol, Host, Path, Document, Port, Bookmark: string;
1621 begin
1622         Result := ParentBoard.URL
1623                                         + 'dat/'
1624                                         + FileName;
1625         if FDownloadHost <> '' then begin
1626                 GikoSys.ParseURI(Result, Protocol, Host, Path, Document, Port, Bookmark);
1627                 Result := Format('%s://%s%s%s', [Protocol,
1628                                                                                                                                                  FDownloadHost,
1629                                                                                                                                                  Path,
1630                                                                                                                                                  Document]);
1631         end;
1632 //      Result := GikoSys.UrlToServer(ParentBoard.URL)
1633 //                                      + 'test/read.cgi/' + ParentBoard.BBSID + '/'
1634 //                                      + ChangeFileExt(FileName, '') + '/?raw='
1635 //                                      + IntToStr(ResNum) + '.' + IntToStr(ResSize);
1636 end;
1637
1638 function TThreadItem.GetDatgzURL: string;
1639         function isOldKako(s: string): Boolean;
1640         begin
1641                 Result := False;
1642                 if AnsiPos('piza.', s) <> 0 then
1643                         Result := True
1644                 else if AnsiPos('www.bbspink.', s) <> 0 then
1645                         Result := True
1646                 else if AnsiPos('tako.', s) <> 0 then
1647                         Result := True;
1648         end;
1649 var
1650         Protocol, Host, Path, Document, Port, Bookmark: string;
1651         DatNo: string;
1652 begin
1653         if FDownloadHost = '' then begin
1654                 DatNo := ChangeFileExt(FileName, '');
1655                 if isOldKako(ParentBoard.URL) then begin
1656                         Result := Format('%s%s/%.3s/%s.dat', [ParentBoard.URL, 'kako', DatNo, DatNo]);
1657                 end else begin
1658                         if Length(DatNo) > 9 then begin
1659                                 //http://xxx.2ch.net/xxx/kako/9999/99999/999999999.dat.gz
1660                                 Result := Format('%s%s/%.4s/%.5s/%s.dat.gz', [ParentBoard.URL, 'kako', DatNo, DatNo, DatNo]);
1661                         end else begin
1662                                 //http://xxx.2ch.net/xxx/kako/999/999999999.dat.gz
1663                                 Result := Format('%s%s/%.3s/%s.dat.gz', [ParentBoard.URL, 'kako', DatNo, DatNo]);
1664                         end;
1665                 end;
1666         end else begin
1667                 Gikosys.ParseURI(Result, Protocol, Host, Path, Document, Port, Bookmark);
1668                 DatNo := ChangeFileExt(Document, '');
1669                 if isOldKako(DownloadHost) then begin
1670                         Result := Format('%s://%s/%s/kako/%.3s/%s.dat', [Protocol, DownloadHost, ParentBoard.FBBSID, DatNo, DatNo]);
1671                 end else begin
1672                         if Length(DatNo) > 9 then begin
1673                                 Result := Format('%s://%s/%s/kako/%.4s/%.5s/%s.dat.gz', [Protocol, DownloadHost, ParentBoard.FBBSID, DatNo, DatNo, DatNo]);
1674                         end else begin
1675                                 Result := Format('%s://%s/%s/kako/%.3s/%s.dat.gz', [Protocol, DownloadHost, ParentBoard.FBBSID, DatNo, DatNo]);
1676                         end;
1677                 end;
1678         end;
1679 end;
1680
1681 function TThreadItem.GetOfflawCgiURL(const SessionID: string): string;
1682 begin
1683         if FDownloadHost = '' then begin
1684                 Result := GikoSys.UrlToServer(ParentBoard.URL)
1685                                                 + 'test/offlaw.cgi/' + ParentBoard.BBSID + '/'
1686                                                 + ChangeFileExt(FileName, '') + '/?raw=.0&sid=' + HttpEncode(SessionID);
1687         end else begin
1688                 //http://news.2ch.net/test/offlaw.cgi/newsplus/1014038577/?raw=.196928&sid=
1689                 //GikoSys.ParseURI(Result, Protocol, Host, Path, Document, Port, Bookmark);
1690                 Result := 'http://' + FDownloadHost
1691                                                 + '/test/offlaw.cgi/' + ParentBoard.BBSID + '/'
1692                                                 + ChangeFileExt(FileName, '') + '/?raw=.0&sid=' + HttpEncode(SessionID);
1693         end;
1694 end;
1695
1696 //////////////// 2013/10/13 ShiroKuma\91Î\89\9e zako Start ///////////////////////////
1697 function TThreadItem.GetOfflaw2SoURL: string;
1698 begin
1699         if FDownloadHost = '' then begin
1700                 Result := GikoSys.UrlToServer(ParentBoard.URL)
1701                                                 + 'test/offlaw2.so?shiro=kuma&bbs=' + ParentBoard.BBSID
1702                         + '&key=' + ChangeFileExt(FileName, '');
1703         end else begin
1704                 Result := 'http://' + FDownloadHost
1705                                                 + '/test/offlaw2.so?shiro=kuma&bbs=' + ParentBoard.BBSID
1706                         + '&key=' + ChangeFileExt(FileName, '');
1707         end;
1708 end;
1709 //////////////// 2013/10/13 ShiroKuma\91Î\89\9e zako End /////////////////////////////
1710
1711 //////////////// 2014/03/08 Rokka\91Î\89\9e zako Start ///////////////////////////////
1712 function TThreadItem.GetRokkaURL(const SessionID: string): string;
1713 var
1714     Domain: string;
1715     Host: string;
1716     Idx: Integer;
1717     HostPos: Integer;
1718 begin
1719         if FDownloadHost = '' then begin
1720         Idx := AnsiPos('.2ch.net/', ParentBoard.URL);
1721         if (Idx > 0) then begin
1722             Domain := '2ch.net';
1723         end else begin
1724             Idx := AnsiPos('.bbspink.com/', ParentBoard.URL);
1725             if (Idx > 0) then
1726                 Domain := 'bbspink.com';
1727         end;
1728         if (Idx > 0) then begin
1729             HostPos := AnsiPos('://', ParentBoard.URL) + 3;
1730             Host := Copy(ParentBoard.URL, HostPos, Idx - HostPos);
1731         end;
1732     end else begin
1733         Idx := AnsiPos('.2ch.net', FDownloadHost);
1734         if (Idx > 0) then begin
1735             Domain := '2ch.net';
1736         end else begin
1737             Idx := AnsiPos('.bbspink.com', FDownloadHost);
1738             if (Idx > 0) then
1739                 Domain := 'bbspink.com';
1740         end;
1741         if (Idx > 0) then begin
1742             Host := Copy(FDownloadHost, 1, Idx - 1);
1743         end;
1744     end;
1745
1746     if ((Domain = '') or (Host = '')) then
1747         Result := ''
1748     else
1749         Result := 'http://rokka.' + Domain + '/' + Host + '/'
1750                 + ParentBoard.BBSID + '/' + ChangeFileExt(FileName, '')
1751                 + '/?sid=' + SessionID;
1752 end;
1753 //////////////// 2014/03/08 Rokka\91Î\89\9e zako End /////////////////////////////////
1754
1755
1756 // \8aO\95\94\94Â\89ß\8b\8e\83\8d\83OURL\8eæ\93¾
1757 function TThreadItem.GetExternalBoardKakoDatURL: string;
1758 var
1759         DatNo: string;
1760 begin
1761         DatNo := ChangeFileExt(FileName, '');
1762         //http://xxx.vip2ch.com/xxx/kako/1234/12345/1234567890.dat
1763         Result := Format('%s%s/%.4s/%.5s/%s.dat', [ParentBoard.URL, 'kako', DatNo, DatNo, DatNo]);
1764 end;
1765 // \8aO\95\94\94Â\89ß\8b\8e\83\8d\83OURL\8eæ\93¾
1766
1767 function TThreadItem.GetSendURL: string;
1768 begin
1769         Result := GikoSys.UrlToServer(ParentBoard.URL)
1770                                         + 'test/bbs.cgi';
1771 end;
1772
1773 procedure TThreadItem.DeleteLogFile;
1774 var
1775         tmpFileName: String;
1776 begin
1777         ParentBoard.BeginUpdate;
1778
1779         if FUnRead then
1780                 ParentBoard.UnRead := ParentBoard.UnRead - 1;
1781         DeleteFile(GetThreadFileName);
1782         //\8e\8e\8c±\93I\82Étmp\82à\8dí\8f\9c\82µ\82Ä\82Ý\82é
1783         tmpFileName := StringReplace(GetThreadFileName, 'dat', 'tmp', [rfReplaceAll]);
1784         DeleteFile(tmpFileName);
1785
1786         if FileExists(ChangeFileExt(GetThreadFileName,'.NG')) = true then
1787                 DeleteFile(ChangeFileExt(GetThreadFileName,'.NG'));
1788         FRoundDate := ZERO_DATE;
1789         FLastModified := ZERO_DATE;
1790         FSize := 0;
1791         FIsLogFile := False;
1792         FKokomade := -1;
1793         FNewReceive := 0;
1794         FNewArrival := False;
1795         FUnRead := False;
1796         FScrollTop := 0;
1797         FRound := False;
1798         FDownloadHost := '';
1799         FAgeSage := gasNone;
1800
1801         FCount := 0;
1802         FNewResCount := 0;
1803         FRoundName := '';
1804
1805         ParentBoard.EndUpdate;
1806         ParentBoard.Modified := True;
1807 end;
1808
1809 function TThreadItem.GetThreadFileName: string;
1810 begin
1811         if Length( FilePath ) > 0 then
1812                 Result := FilePath
1813         else
1814                 Result := GikoSys.Setting.LogFolderP
1815                                                 + BBS2CH_LOG_FOLDER + PATH_DELIM + ParentBoard.BBSID + PATH_DELIM + FileName;
1816 end;
1817
1818 procedure TThreadItem.SetLastModified(d: TDateTime);
1819 begin
1820         if FLastModified = d then Exit;
1821         FLastModified := d;
1822         if FUpdate and (ParentBoard <> nil) then
1823                 ParentBoard.FModified := True;
1824 end;
1825
1826 procedure TThreadItem.SetRound(b: Boolean);
1827 begin
1828         if b then
1829                 RoundList.Add(Self)
1830         else
1831                 RoundList.Delete(Self);
1832         if FRound = b then Exit;
1833         FRound := b;
1834         if FUpdate and (ParentBoard <> nil) then
1835                 ParentBoard.FModified := True;
1836 end;
1837
1838 procedure TThreadItem.SetRoundName(const s: string);
1839 begin
1840         if FRoundName = s then Exit;
1841         FRoundName := s;
1842         if FUpdate and (ParentBoard <> nil) then
1843                 ParentBoard.FModified := True;
1844 end;
1845
1846
1847 procedure TThreadItem.SetKokomade(i: Integer);
1848 begin
1849         if FKokomade = i then Exit;
1850         FKokomade := i;
1851         if FUpdate and (ParentBoard <> nil) then
1852                 ParentBoard.FModified := True;
1853 end;
1854
1855 procedure TThreadItem.SetUnRead(b: Boolean);
1856 begin
1857         if FUnRead = b then Exit;
1858         FUnRead := b;
1859         if FUpdate and (ParentBoard <> nil) then begin
1860                 ParentBoard.FModified := True;
1861                 if FUnRead then begin
1862                         ParentBoard.UnRead := ParentBoard.UnRead + 1;
1863                 end else begin
1864             ParentBoard.UnRead := ParentBoard.UnRead - 1;
1865                 end;
1866         end;
1867 end;
1868
1869 procedure TThreadItem.SetScrollTop(i: Integer);
1870 begin
1871         if FScrollTop = i then Exit;
1872         FScrollTop := i;
1873         if FUpdate and (ParentBoard <> nil) then
1874                 ParentBoard.FModified := True;
1875 end;
1876
1877 procedure TThreadItem.BeginUpdate;
1878 begin
1879         FUpdate := False;
1880 end;
1881
1882 procedure TThreadItem.EndUpdate;
1883 begin
1884         FUpdate := True;
1885 end;
1886
1887 function TThreadItem.GetCreateDate: TDateTime;
1888 begin
1889         // \83t\83@\83C\83\8b\96¼\82©\82ç\83X\83\8c\8dì\90¬\93ú\8e\9e\82ð\8b\81\82ß\82é
1890         try
1891                 if ( GikoSys.Setting.CreationTimeLogs ) and not IsLogFile  then
1892             Result := ZERO_DATE
1893         else begin
1894             // \83\8d\83O\83t\83@\83C\83\8b\82Ì\8ag\92£\8eq\82ð\82Í\82¸\82µ\82½\82à\82Ì\82ª\83X\83\8c\8dì\90¬\93ú\8e\9e
1895             Result := GikoSys.GetCreateDateFromName(FFileName);
1896                         if GikoSys.Setting.FutureThread then begin
1897                         if CompareDateTime(Result, Now) = 1 then
1898                         Result := ZERO_DATE;
1899                 end;
1900         end;
1901
1902         except
1903                 on E: Exception do
1904                         Result := ZERO_DATE;
1905         end;
1906 end;
1907 function TThreadItem.GetFilePath: String;
1908 var
1909         path : String;
1910 begin
1911         path := ExtractFilePath(Self.ParentBoard.FilePath) + Self.FileName;
1912     Result := path;
1913 end;
1914
1915 destructor TBoardGroup.Destroy;
1916 begin
1917         Clear;
1918         inherited;
1919 end;
1920 procedure       TBoardGroup.Clear;
1921 var
1922         i       : Integer;
1923 begin
1924         for i := Self.Count - 1 downto 0 do begin
1925                 try
1926                         TBoard(Self.Objects[i]).Free;
1927                 except
1928                 end;
1929     end;
1930     inherited Clear;
1931         Self.Capacity := 0;
1932         try
1933                 if FBoardPlugIn <> nil then
1934                         FBoardPlugIn.Free;
1935         FBoardPlugIn := nil;
1936         except
1937         end;
1938
1939 end;
1940
1941 function TSpecialBoard.Add(item: TThreadItem): integer;
1942 begin
1943     Result := inherited AddObject(Item.URL, Item);
1944 end;
1945
1946 procedure TSpecialBoard.Clear;
1947 var
1948         i: integer;
1949 begin
1950     for i := Count - 1 downto 0 do
1951                 DeleteList(i);
1952     Capacity := 0;
1953 end;
1954
1955 end.
1956