OSDN Git Service

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