OSDN Git Service

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