OSDN Git Service

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