OSDN Git Service

"/test/read.cgi"のリンクを拡張して"/test/read.html"でも同様に処理できるようにした。
[gikonavigoeson/gikonavi.git] / GikoSystem.pas
1 unit GikoSystem;
2
3 interface
4
5 uses
6         Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
7         ComCtrls, {IniFiles,} ShellAPI, ActnList, Math,
8 {$IF Defined(DELPRO) }
9         SHDocVw,
10         MSHTML,
11 {$ELSE}
12         SHDocVw_TLB,
13         MSHTML_TLB,
14 {$IFEND}
15         {HttpApp,} URLMon, IdGlobal, IdURI, {Masks,}
16         Setting, BoardGroup, gzip, Dolib, bmRegExp, AbonUnit,
17         ExternalBoardManager, ExternalBoardPlugInMain,
18         GikoBayesian, GikoMessage;
19
20 type
21         TVerResourceKey = (
22                         vrComments,         //!< \83R\83\81\83\93\83g
23                         vrCompanyName,      //!< \89ï\8eÐ\96¼
24                         vrFileDescription,  //!< \90à\96¾
25                         vrFileVersion,      //!< \83t\83@\83C\83\8b\83o\81[\83W\83\87\83\93
26                         vrInternalName,     //!< \93à\95\94\96¼
27                         vrLegalCopyright,   //!< \92\98\8dì\8c 
28                         vrLegalTrademarks,  //!< \8f¤\95W
29                         vrOriginalFilename, //!< \90³\8e®\83t\83@\83C\83\8b\96¼
30                         vrPrivateBuild,     //!< \83v\83\89\83C\83x\81[\83g\83r\83\8b\83h\8fî\95ñ
31                         vrProductName,      //!< \90»\95i\96¼
32                         vrProductVersion,   //!< \90»\95i\83o\81[\83W\83\87\83\93
33                         vrSpecialBuild);    //!< \83X\83y\83V\83\83\83\8b\83r\83\8b\83h\8fî\95ñ
34
35         //! BBS\83^\83C\83v
36         TGikoBBSType = (gbt2ch);
37         //! \83\8d\83O\83^\83C\83v
38         TGikoLogType = (glt2chNew, glt2chOld);
39         //! \83\81\83b\83Z\81[\83W\83A\83C\83R\83\93
40         TGikoMessageIcon = (gmiOK, gmiSAD, gmiNG, gmiWhat, gmiNone);
41         //! URL\83I\81[\83v\83\93\83u\83\89\83E\83U\83^\83C\83v
42         TGikoBrowserType = (gbtIE, gbtUserApp, gbtAuto);
43
44
45         TStrTokSeparator = set of Char;
46         TStrTokRec = record
47                 Str: string;
48                 Pos: Integer;
49         end;
50
51         //! \83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b\83\8c\83R\81[\83h
52         TIndexRec = record
53                 FNo: Integer;
54                 FFileName: string;
55                 FTitle: string;
56                 FCount: Integer;
57                 FSize: Integer;
58 //              FRoundNo: Integer;
59                 FRoundDate: TDateTime;
60                 FLastModified: TDateTime;
61                 FKokomade: Integer;
62                 FNewReceive: Integer;
63                 FMishiyou: Boolean;     //!< \96¢\8eg\97p
64                 FUnRead: Boolean;
65                 FScrollTop: Integer;
66                 //Index Ver 1.01
67                 FAllResCount: Integer;
68                 FNewResCount: Integer;
69                 FAgeSage: TGikoAgeSage;
70         end;
71
72         //! \83T\83u\83W\83F\83N\83g\83\8c\83R\81[\83h
73         TSubjectRec = record
74                 FFileName: string;
75                 FTitle: string;
76                 FCount: Integer;
77         end;
78
79         //! \83\8c\83X\83\8c\83R\81[\83h\82Ö\82Ì\83|\83C\83\93\83^
80         PResRec = ^TResRec;
81
82         //! \83\8c\83X\83\8c\83R\81[\83h
83         TResRec = record
84                 FTitle: string;
85                 FMailTo: string;
86                 FName: string;
87                 FDateTime: string;
88                 FBody: string;
89                 FType: TGikoLogType;
90         end;
91
92         //! URLPath\83\8c\83R\81[\83h
93         TPathRec = record
94                 FBBS: string;                           //!< BBSID
95                 FKey: string;                           //!< ThreadID
96                 FSt: Int64;                               //!< \8aJ\8en\83\8c\83X\94Ô
97                 FTo: Int64;                               //!< \8fI\97¹\83\8c\83X\94Ô
98                 FFirst: Boolean;                //!< >>1\82Ì\95\\8e¦
99                 FStBegin: Boolean;      //!< 1\81`\95\\8e¦
100                 FToEnd: Boolean;                //!< \81`\8dÅ\8cã\82Ü\82Å\95\\8e¦
101                 FDone: Boolean;                 //!< \90¬\8c÷
102                 FNoParam: Boolean;  //!< \83\8c\83X\94Ô\83p\83\89\83\81\81[\83^\82È\82µ
103         end;
104
105         TGikoSys = class(TObject)
106         private
107                 { Private \90é\8c¾ }
108                 FSetting: TSetting;
109                 FDolib: TDolib;
110                 FAWKStr: TAWKStr;
111                 FResRange : Longint;
112                 FBayesian       : TGikoBayesian;        //!< \83x\83C\83W\83A\83\93\83t\83B\83\8b\83^
113                 FVersion : String;                    //!< \83t\83@\83C\83\8b\83o\81[\83W\83\87\83\93
114                 FGikoMessage: TGikoMessage;
115                 //! \82 \82é\83Z\83p\83\8c\81[\83^\82Å\8bæ\90Ø\82ç\82ê\82½\95\8e\9a\97ñ\82©\82ç\82\8e\94Ô\96Ú\82Ì\95\8e\9a\97ñ\82ð\8eæ\82è\8fo\82·
116                 function ChooseString(const Text, Separator: string; Index: integer): string;
117         //! \88ê\8e\9e\83t\83@\83C\83\8b\82©\82ç\82Ì\95\9c\8b\8c
118         procedure RestoreThreadData(Board: TBoard);
119         public
120                 { Public \90é\8c¾ }
121                 FAbon : TAbon;
122                 FSelectResFilter : TAbon;
123                 //FBoardURLList: TStringList;
124                 constructor Create;
125
126                 destructor Destroy; override;
127                 property ResRange : Longint read FResRange write FResRange;
128                 //! \83o\81[\83W\83\87\83\93\8fî\95ñ
129                 property Version : String read FVersion;
130                 function IsNumeric(s: string): boolean;
131                 function IsFloat(s: string): boolean;
132                 function DirectoryExistsEx(const Name: string): Boolean;
133                 function ForceDirectoriesEx(Dir: string): Boolean;
134
135                 function GetBoardFileName: string;
136                 function GetCustomBoardFileName: string;
137                 function GetHtmlTempFileName: string;
138                 function GetAppDir: string;
139                 function GetTempFolder: string;
140                 function GetSentFileName: string;
141                 function GetConfigDir: string;
142                 function GetSkinDir: string;
143                 function GetSkinHeaderFileName: string;
144                 function GetSkinFooterFileName: string;
145                 function GetSkinResFileName: string;
146                 function GetSkinNewResFileName: string;
147                 function GetSkinBookmarkFileName: string;
148                 function GetSkinNewmarkFileName: string;
149                 function GetStyleSheetDir: string;
150                 function GetOutBoxFileName: string;
151                 function GetUserAgent: string;
152                                 function GetSambaFileName : string;
153
154                 function GetMainKeyFileName : String;
155                 function GetEditorKeyFileName: String;
156                 function GetInputAssistFileName: String;
157                 procedure ReadSubjectFile(Board: TBoard);
158                 procedure CreateThreadDat(Board: TBoard);
159                 procedure WriteThreadDat(Board: TBoard);
160                 function ParseIndexLine(Line: string): TIndexRec;
161                 procedure GetFileList(Path: string; Mask: string; var List: TStringList; SubDir: Boolean; IsPathAdd: Boolean); overload;
162                 procedure GetFileList(Path: string; Mask: string; var List: TStringList; IsPathAdd: Boolean); overload;//\83T\83u\83t\83H\83\8b\83_\82Í\8c\9f\8dõ\82µ\82È\82¢
163                 procedure GetDirectoryList(Path: string; Mask: string; List: TStringList; SubDir: Boolean);
164
165                 function DivideSubject(Line: string): TSubjectRec;
166                 property Setting: TSetting read FSetting write FSetting;
167                 property Dolib: TDolib read FDolib write FDolib;
168
169                 function UrlToID(url: string): string;
170                 function UrlToServer(url: string): string;
171
172                 function StrTokFirst(const s:string; const sep:TStrTokSeparator; var Rec:TStrTokRec):string;
173                 function StrTokNext(const sep:TStrTokSeparator; var Rec:TStrTokRec): string;
174
175                 function GetFileSize(FileName : string) : longint;
176                 function GetFileLineCount(FileName : string): longint;
177                 function IntToDateTime(val: Int64): TDateTime;
178                 function DateTimeToInt(ADate: TDateTime): Int64;
179
180                 function ReadThreadFile(FileName: string; Line: Integer): string;
181
182                 procedure MenuFont(Font: TFont);
183
184                 function RemoveToken(var s:string; const delimiter:string):string;
185                 function GetTokenIndex(s: string; delimiter: string; index: Integer): string;
186
187                 function GetShortName(const LongName: string; ALength: integer): string;
188                 function BoolToInt(b: Boolean): Integer;
189                 function IntToBool(i: Integer): Boolean;
190                 function GzipDecompress(ResStream: TStream; ContentEncoding: string): string;
191                 procedure LoadKeySetting(ActionList: TActionList; FileName: String);
192                 procedure SaveKeySetting(ActionList: TActionList; FileName: String);
193                 procedure CreateProcess(const AppPath: string; const Param: string);
194                 procedure OpenBrowser(URL: string; BrowserType: TGikoBrowserType);
195                 function HTMLDecode(const AStr: String): String;
196                 function GetHRefText(s: string): string;
197                 function Is2chHost(Host: string): Boolean;
198                 function Parse2chURL(const url: string; const path: string; const document: string; var BBSID: string; var BBSKey: string): Boolean;
199                 function Parse2chURL2(URL: string): TPathRec;
200                 procedure ParseURI(const URL : string; var Protocol, Host, Path, Document, Port, Bookmark: string);
201                 function GetVersionBuild: Integer;
202                 function        GetBrowsableThreadURL( inURL : string ) : string;
203                 function        GetThreadURL2BoardURL( inURL : string ) : string;
204                 function        Get2chThreadURL2BoardURL( inURL : string ) : string;
205                 function        Get2chBrowsableThreadURL( inURL : string ) : string;
206                 function        Get2chBoard2ThreadURL( inBoard : TBoard; inKey : string ) : string;
207                 procedure ListBoardFile;
208                 procedure ReadBoardFile( bbs : TBBS );
209
210                 function        GetUnknownCategory : TCategory;
211                 function        GetUnknownBoard( inPlugIn : TBoardPlugIn; inURL : string ) : TBoard;
212
213                 procedure GetPopupResNumber(URL : string; var stRes, endRes : Int64);
214
215                 property Bayesian : TGikoBayesian read FBayesian write FBayesian;
216                 function GetSameIDResAnchor(const AID : string; ThreadItem: TThreadItem; limited: Integer):string; overload;
217                 function GetSameIDResAnchor(AIDNum : Integer; ThreadItem: TThreadItem; limited: Integer):string; overload;
218                 procedure GetSameIDRes(const AID : string; ThreadItem: TThreadItem;var body: TStringList); overload;
219                 procedure GetSameIDRes(AIDNum : Integer; ThreadItem: TThreadItem;var body: TStringList); overload;
220                 function GetSameIDResCount(const AID : string; ThreadItem: TThreadItem):Integer; overload;
221                 function GetSameIDResCount(AIDNum : Integer; ThreadItem: TThreadItem):Integer; overload;
222         function GetResID(AIDNum: Integer; ThreadItem: TThreadItem): String;
223                 //! \92P\8cê\89ð\90Í
224                 procedure SpamCountWord( const text : string; wordCount : TWordCount );
225                 //! \8aw\8fK\83N\83\8a\83A
226                 procedure SpamForget( wordCount : TWordCount; isSpam : Boolean );
227                 //! \83X\83p\83\80\8aw\8fK
228                 procedure SpamLearn( wordCount : TWordCount; isSpam : Boolean );
229                 //! \83X\83p\83\80\93x\90\94
230                 function SpamParse( const text : string; wordCount : TWordCount ) : Extended;
231                 //\88ø\90\94\82ª\81A\93ú\95t\82Å\82à\8e\9e\8d\8f\82Å\82à\82È\82¢\82±\82Æ\82ð\92²\82×\82é
232                 function NotDateorTimeString(const AStr : string): boolean;
233
234                 //! \88ø\90\94\82É\91\97\82ç\82ê\82Ä\82«\82½\93ú\95t/ID\95\94\82ÉBE\82Ì\95\8e\9a\97ñ\82ª\82 \82Á\82½\82ç\81A\83v\83\8d\83t\83@\83C\83\8b\82Ö\82Ì\83\8a\83\93\83N\82ð\92Ç\89Á
235                 function AddBeProfileLink(AID : string; ANum: Integer): string;
236                 //! \83o\81[\83W\83\87\83\93\8fî\95ñ\82Ì\8eæ\93¾
237                 function GetVersionInfo(KeyWord: TVerResourceKey): string;
238                 //! Plugin\82Ì\8fî\95ñ\82Ì\8eæ\93¾
239                 function GetPluginsInfo(): string;
240                 //! IE\82Ì\83o\81[\83W\83\87\83\93\8fî\95ñ\82Ì\8eæ\93¾
241                 function GetIEVersion: string;
242                 function SetUserOptionalStyle(): string;
243                 //! \83M\83R\83i\83r\82Ì\83\81\83b\83Z\81[\83W\82ð\90Ý\92è\82·\82é
244                 procedure SetGikoMessage;
245                 //! \83M\83R\83i\83r\82Ì\83\81\83b\83Z\81[\83W\82ð\8eæ\93¾\82·\82é
246                 function GetGikoMessage(MesType: TGikoMessageListType): String;
247                 //! GMT\82Ì\8e\9e\8d\8f\82ðTDateTime\82É\95Ï\8a·\82·\82é
248                 function  DateStrToDateTime(const DateStr: string): TDateTime;
249         //! User32.dll\82ª\97\98\97p\82Å\82«\82é\82©
250         function CanUser32DLL: Boolean;
251         //! OE\88ø\97p\95\84\8eæ\93¾
252         function GetOEIndentChar : string;
253         //! \92u\8a·\90Ý\92è\83t\83@\83C\83\8b\8eæ\93¾
254         function GetReplaceFileName: String;
255         //! \83C\83\93\83f\83b\83N\83X\82É\82È\82¢dat\81i\82Í\82®\82êdat\81j\82Ì\92Ç\89Á
256         procedure AddOutofIndexDat(Board: TBoard; DatList: TStringList; AllCreate: boolean = True);
257         //! \83t\83@\83C\83\8b\96¼\82©\82ç\82Ì\83X\83\8c\83b\83h\8dì\90¬\93ú\82Ì\8eæ\93¾
258         function GetCreateDateFromName(FileName: String): TDateTime;
259         function GetExtpreviewFileName: String;
260
261         procedure ShowRefCount(msg: String; unk: IUnknown);
262         end;
263
264 var
265         GikoSys: TGikoSys;
266 const
267         //LENGTH_RESTITLE                       = 40;
268         ZERO_DATE: Integer      = 25569;
269         BETA_VERSION_NAME_E = 'beta';
270         BETA_VERSION_NAME_J = 'ÊÞÀ';
271         BETA_VERSION                            = 58;
272         BETA_VERSION_BUILD      = '';                           //!< debug\94Å\82È\82Ç
273         APP_NAME                                                = 'gikoNavi';
274         BE_PHP_URL = 'http://be.2ch.net/test/p.php?i=';
275
276
277 implementation
278
279 uses
280         Giko, RoundData, Favorite, Registry, HTMLCreate, MojuUtils, Sort, YofUtils,
281         IniFiles, DateUtils, SkinFiles;
282
283 const
284         FOLDER_INDEX_VERSION                                    = '1.01';
285         USER_AGENT                                                                              = 'Monazilla';
286         DEFAULT_NGWORD_FILE_NAME : String = 'NGword.txt';
287         NGWORDs_DIR_NAME : String               = 'NGwords';
288
289         READ_PATH: string =                     '/test/read.cgi/';
290     HTML_READ_PATH: string =        '/test/read.html/';
291         OLD_READ_PATH: string =         '/test/read.cgi?';
292         KAKO_PATH: string =                     '/kako/';
293
294         KeyWordStr: array [TVerResourceKey] of String = (
295                   'Comments',
296                   'CompanyName',
297                   'FileDescription',
298                   'FileVersion',
299                   'InternalName',
300                   'LegalCopyright',
301                   'LegalTrademarks',
302                   'OriginalFilename',
303                   'PrivateBuild',
304                   'ProductName',
305                   'ProductVersion',
306                   'SpecialBuild');
307
308 // *************************************************************************
309 //! GikoSys\83R\83\93\83X\83g\83\89\83N\83^
310 // *************************************************************************
311 constructor TGikoSys.Create;
312 begin
313     Inherited;
314         FSetting := TSetting.Create;
315         FDolib := TDolib.Create;
316         FAWKStr := TAWKStr.Create(nil);
317         if DirectoryExists(GetConfigDir) = false then begin
318                 CreateDir(GetConfigDir);
319         end;
320         FAbon := TAbon.Create;
321     FAbon.IgnoreKana := FSetting.IgnoreKana;
322         FAbon.Setroot(GetConfigDir+NGWORDs_DIR_NAME);
323         FAbon.GoHome;
324         FAbon.ReturnNGwordLineNum := FSetting.ShowNGLinesNum;
325         FAbon.SetNGResAnchor := FSetting.AddResAnchor;
326         FAbon.DeleteSyria := FSetting.DeleteSyria;
327         FAbon.Deleterlo := FSetting.AbonDeleterlo;
328         FAbon.Replaceul := FSetting.AbonReplaceul;
329         FAbon.AbonPopupRes := FSetting.PopUpAbon;
330
331         FSelectResFilter := TAbon.Create;
332     FSelectResFilter.IgnoreKana := True;
333         // \8di\82è\8d\9e\82Þ\82Æ\82«\82Í\8bÉ\97Í\88ê\97\97\82ª\8c©\82ç\82ê\82é\82Ù\82¤\82ª\82¢\82¢\82Ì\82Å\91¼\82Í\8a®\91S\82É\8dí\8f\9c
334         FSelectResFilter.AbonString := '';
335     //
336         ResRange := FSetting.ResRange;
337         FVersion := Trim(GetVersionInfo(vrFileVersion));
338         FBayesian := TGikoBayesian.Create;
339         //FBoardURLList := TStringList.Create;
340         //\83\81\83b\83Z\81[\83W\82Ì\8dì\90¬
341         FGikoMessage := TGikoMessage.Create;
342 end;
343
344 // *************************************************************************
345 //! GikoSys\83f\83X\83g\83\89\83N\83^
346 // *************************************************************************
347 destructor TGikoSys.Destroy;
348 var
349         i: Integer;
350         FileList: TStringList;
351 begin
352         //\83e\83\93\83|\83\89\83\8aHTML\82ð\8dí\8f\9c
353         FileList := TStringList.Create;
354         try
355         FileList.BeginUpdate;
356                 GetFileList(GetTempFolder, '*.html', FileList, False, True);
357         FileList.EndUpdate;
358                 for i := 0 to FileList.Count - 1 do begin
359                         DeleteFile(FileList[i]);
360                 end;
361         finally
362                 FileList.Free;
363         end;
364     FreeAndNil(FGikoMessage);
365         FreeAndNil(FBayesian);
366         FreeAndNil(FSelectResFilter);
367         FreeAndNil(FAbon);
368         FreeAndNil(FAWKStr);
369         FreeAndNil(FDolib);
370         FreeAndNil(FSetting);
371         inherited;
372 end;
373
374 {!
375 \brief \95\8e\9a\97ñ\90\94\8e\9a\83`\83F\83b\83N
376 \param s \83`\83F\83b\83N\82·\82é\95\8e\9a\97ñ
377 \return s \82ª\95\84\8d\86\95t\82«\90®\90\94\82Æ\82µ\82Ä\94F\8e¯\89Â\94\\82È\82ç True
378 }
379 {$HINTS OFF}
380 function TGikoSys.IsNumeric(s: string): boolean;
381 var
382         e: integer;
383         v: integer;
384 begin
385         Val(s, v, e);
386         Result := e = 0;
387 end;
388 {$HINTS ON}
389
390 {!
391 \brief \95\8e\9a\97ñ\95\82\93®\8f¬\90\94\93_\90\94\8e\9a\83`\83F\83b\83N
392 \param s \83`\83F\83b\83N\82·\82é\95\8e\9a\97ñ
393 \return s \82ª\95\84\8d\86\95t\82«\95\82\93®\8f¬\90\94\82Æ\82µ\82Ä\94F\8e¯\89Â\94\\82È\82ç True
394 }
395 function TGikoSys.IsFloat(s: string): boolean;
396 var
397         v: Extended;
398 begin
399         Result := TextToFloat(PChar(s), v, fvExtended);
400 end;
401
402 // *************************************************************************
403 //! \83{\81[\83h\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
404 // *************************************************************************
405 function TGikoSys.GetBoardFileName: string;
406 begin
407         Result := Setting.GetBoardFileName;
408 end;
409
410 // *************************************************************************
411 //! \83{\81[\83h\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
412 // *************************************************************************
413 function TGikoSys.GetCustomBoardFileName: string;
414 begin
415         Result := Setting.GetCustomBoardFileName;
416 end;
417
418 // *************************************************************************
419 //! \83e\83\93\83|\83\89\83\8a\83t\83H\83\8b\83_\81[\96¼\8eæ\93¾
420 // *************************************************************************
421 function TGikoSys.GetHtmlTempFileName: string;
422 begin
423         Result := Setting.GetHtmlTempFileName;
424 end;
425
426
427 // *************************************************************************
428 //! \8eÀ\8ds\83t\83@\83C\83\8b\83t\83H\83\8b\83_\8eæ\93¾
429 // *************************************************************************
430 function TGikoSys.GetAppDir: string;
431 begin
432         Result := Setting.GetAppDir;
433 end;
434
435 // *************************************************************************
436 //! TempHtml\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
437 // *************************************************************************
438 function TGikoSys.GetTempFolder: string;
439 begin
440         Result := Setting.GetTempFolder;
441 end;
442
443 // *************************************************************************
444 //! sent.ini\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
445 // *************************************************************************)
446 function TGikoSys.GetSentFileName: string;
447 begin
448         Result := Setting.GetSentFileName;
449 end;
450
451 // *************************************************************************
452 //! outbox.ini\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
453 // *************************************************************************
454 function TGikoSys.GetOutBoxFileName: string;
455 begin
456         Result := Setting.GetOutBoxFileName;
457 end;
458
459 // *************************************************************************
460 //! Config\83t\83H\83\8b\83_\8eæ\93¾
461 // *************************************************************************
462 function TGikoSys.GetConfigDir: string;
463 begin
464         Result := Setting.GetConfigDir;
465 end;
466
467 //! \83X\83^\83C\83\8b\83V\81[\83g\83t\83H\83\8b\83_
468 function TGikoSys.GetStyleSheetDir: string;
469 begin
470         Result := Setting.GetStyleSheetDir;
471 end;
472
473 //! \83X\83L\83\93\83t\83H\83\8b\83_
474 function TGikoSys.GetSkinDir: string;
475 begin
476         Result := Setting.GetSkinDir;
477 end;
478
479 //! Skin:\83w\83b\83_\82Ì\83t\83@\83C\83\8b\96¼
480 function TGikoSys.GetSkinHeaderFileName: string;
481 begin
482         Result := Setting.SkinFiles.GetSkinHeaderFileName;
483 end;
484
485 //! Skin:\83t\83b\83^\82Ì\83t\83@\83C\83\8b\96¼
486 function TGikoSys.GetSkinFooterFileName: string;
487 begin
488         Result := Setting.SkinFiles.GetSkinFooterFileName;
489 end;
490
491 //! Skin:\90V\92\85\83\8c\83X\82Ì\83t\83@\83C\83\8b\96¼
492 function TGikoSys.GetSkinNewResFileName: string;
493 begin
494         Result := Setting.SkinFiles.GetSkinNewResFileName;
495 end;
496
497 //! Skin:\94ñ\90V\92\85\83\8c\83X\82Ì\83t\83@\83C\83\8b\96¼
498 function TGikoSys.GetSkinResFileName: string;
499 begin
500         Result := Setting.SkinFiles.GetSkinResFileName;
501 end;
502
503 //! Skin:\82µ\82¨\82è(\82±\82±\82Ü\82Å\93Ç\82ñ\82¾)\82Ì\83t\83@\83C\83\8b\96¼
504 function TGikoSys.GetSkinBookmarkFileName: string;
505 begin
506         Result := Setting.SkinFiles.GetSkinBookmarkFileName;
507 end;
508
509 //! Skin:\82µ\82¨\82è(\90V\92\85\83\8c\83X)\82Ì\83t\83@\83C\83\8b\96¼
510 function TGikoSys.GetSkinNewmarkFileName: string;
511 begin
512         Result := Setting.SkinFiles.GetSkinNewmarkFileName;
513 end;
514
515 //! UserAgent\8eæ\93¾
516 function TGikoSys.GetUserAgent: string;
517 begin
518         if Dolib.Connected then begin
519                 Result := Format('%s %s/%s%d/%s', [
520                                                                 Dolib.UserAgent,
521                                                                 APP_NAME,
522                                                                 BETA_VERSION_NAME_E,
523                                                                 BETA_VERSION,
524                                                                 Version]);
525         end else begin
526                 Result := Format('%s/%s %s/%s%d/%s', [
527                                                                 USER_AGENT,
528                                                                 Dolib.Version,
529                                                                 APP_NAME,
530                                                                 BETA_VERSION_NAME_E,
531                                                                 BETA_VERSION,
532                                                                 Version]);
533         end;
534 end;
535
536 {!
537 \brief \8co\89ß\95b\82ð TDateTime \82É\95Ï\8a·
538 \param val 1970/1/1/ 00:00:00 \82©\82ç\82Ì\8co\89ß\95b
539 \return val \82ð\8e¦\82· TDateTime
540 }
541 function TGikoSys.IntToDateTime(val: Int64): TDateTime;
542 begin
543         Result := ZERO_DATE + val / 86400.0;
544 end;
545
546 {!
547 \brief TDateTime \82ð\8co\89ß\95b\82É\95Ï\8a·
548 \param ADate \95Ï\8a·\82·\82é\8e\9e\8d\8f
549 \return 1970/1/1/ 00:00:00 \82©\82ç\82Ì\8co\89ß\95b
550 }
551 function TGikoSys.DateTimeToInt(ADate: TDateTime): Int64;
552 begin
553         Result := Trunc((ADate - ZERO_DATE) * 86400);
554 end;
555
556
557 {!
558 \brief Subject\83t\83@\83C\83\8bRead
559 \param Board \83X\83\8c\88ê\97\97\82ð\8eæ\93¾\82·\82é\94Â
560 }
561 procedure TGikoSys.ReadSubjectFile(Board: TBoard);
562 var
563         ThreadItem: TThreadItem;
564         FileName: string;
565         FileList: TStringList;
566         Index: Integer;
567         sl: TStringList;
568         i: Integer;
569         Rec: TIndexRec;
570         UnRead: Integer;
571         usePlugIn : Boolean;
572         islog : Boolean;
573     urlHead: String;
574     datFileCheck: Boolean;
575         {*
576         FavoThreadItem : TFavoriteThreadItem;
577         Node: TTreeNode;
578         *}
579 {$IFDEF DEBUG}
580     st, rt: Cardinal;
581 {$ENDIF}
582 begin
583 {$IFDEF DEBUG}
584         st := GetTickCount;
585 {$ENDIF}
586         if Board.IsThreadDatRead then
587                 Exit;
588         Board.Clear;
589         UnRead := 0;
590         usePlugIn := Board.IsBoardPlugInAvailable;
591         //server :=  UrlToServer( Board.URL );
592     // \83X\83\8c\83b\83h\82Å\8b¤\92Ê\82ÌURL\95\94
593     if Board.is2ch then begin
594         urlHead := UrlToServer( Board.URL ) + 'test/read.cgi/' + Board.BBSID + '/';
595     end else begin
596         urlHead := UrlToServer( Board.URL ) + 'test/read.cgi?bbs=' + Board.BBSID + '&key=';
597     end;
598
599         FileName := Board.GetFolderIndexFileName;
600
601     //
602     datFileCheck := (Setting.CheckDatFile) or (not FileExists(FileName));
603     if (datFileCheck) then begin
604         FileList := TStringList.Create;
605         FileList.Sorted := True;
606         FileList.BeginUpdate;
607         //IsLogFile\97pDAT\83t\83@\83C\83\8b\83\8a\83X\83g
608         GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.dat', FileList, False);
609         FileList.EndUpdate;
610     end;
611
612         // \8fd\95¡\82ð\96h\82®
613         Board.BeginUpdate;
614         Board.Sorted := True;
615         sl := TStringList.Create;
616         try
617                 if FileExists(FileName) then begin
618                         sl.LoadFromFile(FileName);
619                         //\82Q\8ds\96Ú\82©\82ç\81i\82P\8ds\96Ú\82Í\83o\81[\83W\83\87\83\93\81j
620                         for i := sl.Count - 1 downto 1 do begin
621                                 Rec := ParseIndexLine(sl[i]);
622                 if (datFileCheck) then begin
623                                 islog := FileList.Find( Rec.FFileName, Index );
624                 end else begin
625                     islog := (Rec.FSize <> 0) and (Rec.FCount <> 0);
626                 end;
627                                 if usePlugIn then
628                                         ThreadItem := TThreadItem.Create(
629                                                         Board.BoardPlugIn,
630                                                         Board,
631                                                         Board.BoardPlugIn.FileName2ThreadURL( DWORD( Board ), Rec.FFileName ) )
632                                 else begin
633                                         if Board.is2ch then begin
634                                                 ThreadItem := TThreadItem.Create(
635                                                         nil,
636                                                         Board,
637                                                         urlHead + ChangeFileExt( Rec.FFileName, '' ) + '/l50',
638                                                         islog,
639                                                         Rec.FFileName
640                                                         );
641                                         end else begin
642                                                 ThreadItem := TThreadItem.Create(
643                                                         nil,
644                                                         Board,
645                                                         urlHead + ChangeFileExt( Rec.FFileName, '' ) + '&ls=50',
646                                                         islog,
647                                                         Rec.FFileName
648                                                         );
649                                         end;
650                                 end;
651
652                                 ThreadItem.BeginUpdate;
653                                 if (datFileCheck) and (islog) then
654                                         FileList.Delete( Index );
655
656                                 ThreadItem.No := Rec.FNo;
657                                 ThreadItem.FileName := Rec.FFileName;
658                                 ThreadItem.Title := MojuUtils.UnSanitize(Rec.FTitle);
659                                 ThreadItem.Count := Rec.FCount;
660                                 ThreadItem.Size := Rec.FSize;
661                                 ThreadItem.RoundDate := Rec.FRoundDate;
662                                 ThreadItem.LastModified := Rec.FLastModified;
663                                 ThreadItem.Kokomade := Rec.FKokomade;
664                                 ThreadItem.NewReceive := Rec.FNewReceive;
665                                 ThreadItem.UnRead := Rec.FUnRead;
666                                 ThreadItem.ScrollTop := Rec.FScrollTop;
667                                 ThreadItem.AllResCount := Rec.FAllResCount;
668                                 ThreadItem.NewResCount := Rec.FNewResCount;
669                                 ThreadItem.AgeSage := Rec.FAgeSage;
670                                 ThreadItem.ParentBoard := Board;
671                                 {* \82¨\8bC\82É\93ü\82è\91å\97Ê\90\90¬\83R\81[\83h *}
672                                 {*
673                                 FavoThreadItem := TFavoriteThreadItem.Create( ThreadItem.URL, ThreadItem.Title, ThreadItem );
674                                 Node := FavoriteDM.TreeView.Items.AddChildObject( FavoriteDM.TreeView.Items.Item[0], ThreadItem.Title, FavoThreadItem);
675                                 *}
676
677                                 ThreadItem.EndUpdate;
678                                 Board.Add(ThreadItem);
679
680                                 if (ThreadItem.UnRead) and (ThreadItem.IsLogFile) then
681                                         Inc(UnRead);
682                         end;
683                 end;
684
685                 if UnRead <> Board.UnRead then
686                         Board.UnRead := UnRead;
687
688         if (datFileCheck) then begin
689                     //\83C\83\93\83f\83b\83N\83X\82É\96³\82©\82Á\82½\83\8d\83O\82ð\92Ç\89Á\81i\95\85\82ê\83C\83\93\83f\83b\83N\83X\91Î\89\9e\81j
690             AddOutofIndexDat(Board, FileList);
691         end;
692                 Board.EndUpdate;
693
694         //\91O\89ñ\88Ù\8fí\8fI\97¹\8e\9e\83`\83F\83b\83N
695         RestoreThreadData( Board );
696         finally
697                 sl.Free;
698         if (datFileCheck) then begin
699                 FileList.Free;
700         end;
701                 Board.Sorted := False;
702         end;
703         Board.IsThreadDatRead := True;
704 {$IFDEF DEBUG}
705         rt := GetTickCount - st;
706         Writeln('Read Done.' + IntToStr(rt) + ' ms');
707 {$ENDIF}
708 end;
709 {!
710 \brief \83C\83\93\83f\83b\83N\83X\82É\82È\82¢dat\81i\82Í\82®\82êdat\81j\82Ì\92Ç\89Á
711 \param Board \92Ç\89Á\82·\82é\94Â
712 \param DatList  dat\83t\83@\83C\83\8b\96¼
713 }
714 procedure TGikoSys.AddOutofIndexDat(Board: TBoard; DatList: TStringList; AllCreate: Boolean = True);
715 var
716     i : Integer;
717     Boardpath,FileName : String;
718     ResRec: TResRec;
719     ThreadItem: TThreadItem;
720     create: Boolean;
721 begin
722     create := False;
723     Boardpath := ExtractFilePath(Board.GetFolderIndexFileName);
724     //\83C\83\93\83f\83b\83N\83X\82É\96³\82©\82Á\82½\83\8d\83O\82ð\92Ç\89Á\81i\95\85\82ê\83C\83\93\83f\83b\83N\83X\91Î\89\9e\81j
725     for i := 0 to DatList.Count - 1 do begin
726         FileName := Boardpath + DatList[i];
727         ThreadItem := nil;
728         if (not AllCreate) then begin
729             create := False;
730             ThreadItem := Board.FindThreadFromFileName(DatList[i]);
731             if (ThreadItem = nil) then begin
732                 create := True;
733             end else begin
734                 if Board.IsBoardPlugInAvailable then begin
735                     THTMLCreate.DivideStrLine(Board.BoardPlugIn.GetDat( DWORD( ThreadItem ), 1 ), @ResRec);
736                 end else begin
737                     THTMLCreate.DivideStrLine(ReadThreadFile(FileName, 1), @ResRec);
738                 end;
739             end;
740         end;
741         if (ThreadItem = nil) then begin
742             if Board.IsBoardPlugInAvailable then begin
743                 ThreadItem := TThreadItem.Create(
744                     Board.BoardPlugIn,
745                     Board,
746                     Board.BoardPlugIn.FileName2ThreadURL( DWORD( Board ), DatList[i] ) );
747                 THTMLCreate.DivideStrLine(Board.BoardPlugIn.GetDat( DWORD( ThreadItem ), 1 ), @ResRec);
748             end else begin
749                 ThreadItem := TThreadItem.Create(
750                     nil,
751                     Board,
752                     Get2chBoard2ThreadURL( Board, ChangeFileExt( DatList[i], '' ) ) );
753                 THTMLCreate.DivideStrLine(ReadThreadFile(FileName, 1), @ResRec);
754             end;
755         end;
756         
757
758         ThreadItem.BeginUpdate;
759         ThreadItem.FileName := DatList[i];
760         //ThreadItem.FilePath := FileName;
761         ThreadItem.No := Board.Count + 1;
762         ThreadItem.Title := ResRec.FTitle;
763         ThreadItem.Count := GetFileLineCount(FileName);
764         ThreadItem.AllResCount := ThreadItem.Count;
765         ThreadItem.NewResCount := ThreadItem.Count;
766         ThreadItem.Size := GetFileSize(FileName) - ThreadItem.Count;//1byte\82¸\82ê\82é\82Æ\82«\82ª\82 \82é\82¯\82Ç\82»\82ê\82Í\82 \82«\82ç\82ß\82é
767         ThreadItem.RoundDate := FileDateToDateTime( FileAge( FileName ) );
768         ThreadItem.LastModified := ThreadItem.RoundDate;
769         ThreadItem.Kokomade := -1;
770         ThreadItem.NewReceive := 0;
771         ThreadItem.ParentBoard := Board;
772         ThreadItem.IsLogFile := True;
773         ThreadItem.Round := False;
774         ThreadItem.UnRead := False;
775         ThreadItem.ScrollTop := 0;
776         ThreadItem.AgeSage := gasNone;
777         ThreadItem.EndUpdate;
778         if (AllCreate) or (create) then begin
779             Board.Add(ThreadItem);
780         end;
781     end;
782 end;
783 {!
784 \brief \83X\83\8c\83b\83h\83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b(Folder.idx)\8dì\90¬
785 \param Board Folder.idx \82ð\8dì\90¬\82·\82é\94Â
786 }
787 procedure TGikoSys.CreateThreadDat(Board: TBoard);
788 var
789         i: integer;
790         s: string;
791         SubjectList: TStringList;
792         sl: TStringList;
793         Rec: TSubjectRec;
794         FileName: string;
795         cnt: Integer;
796 begin
797         if not FileExists(Board.GetSubjectFileName) then Exit;
798         FileName := Board.GetFolderIndexFileName;
799
800         SubjectList := TStringList.Create;
801         try
802                 SubjectList.LoadFromFile(Board.GetSubjectFileName);
803                 sl := TStringList.Create;
804                 try
805                         cnt := 1;
806                         sl.BeginUpdate;
807                         sl.Add(FOLDER_INDEX_VERSION);
808                         for i := 0 to SubjectList.Count - 1 do begin
809                                 Rec := DivideSubject(SubjectList[i]);
810
811                                 if (Trim(Rec.FFileName) = '') or (Trim(Rec.FTitle) = '') then
812                                         Continue;
813
814                                 {s := Format('%x', [cnt]) + #1                                  //\94Ô\8d\86
815                                          + Rec.FFileName + #1                                                           //\83t\83@\83C\83\8b\96¼
816                                          + Rec.FTitle + #1                                                                      //\83^\83C\83g\83\8b
817                                          + Format('%x', [Rec.FCount]) + #1      //\83J\83E\83\93\83g
818                                          + Format('%x', [0]) + #1                                               //size
819                                          + Format('%x', [0]) + #1                                               //RoundDate
820                                          + Format('%x', [0]) + #1                                               //LastModified
821                                          + Format('%x', [0]) + #1                                               //Kokomade
822                                          + Format('%x', [0]) + #1                                               //NewReceive
823                                          + '0' + #1                                                                                             //\96¢\8eg\97p
824                                          + Format('%x', [0]) + #1                                               //UnRead
825                                          + Format('%x', [0]) + #1                                               //ScrollTop
826                                          + Format('%x', [Rec.FCount]) + #1      //AllResCount
827                                          + Format('%x', [0]) + #1                                               //NewResCount
828                                          + Format('%x', [0]);                                                           //AgeSage
829                                 }
830                                 s := Format('%x'#1'%s'#1'%s'#1'%x'#1'%x'#1'%x'#1'%x'#1'%x'#1'%x'#1 + 
831                                                         '%s'#1'%x'#1'%x'#1'%x'#1'%x'#1'%x',
832                                         [cnt,                   //\94Ô\8d\86
833                                          Rec.FFileName, //\83t\83@\83C\83\8b\96¼
834                                          MojuUtils.Sanitize(Rec.FTitle),    //\83^\83C\83g\83\8b
835                                          Rec.FCount,     //\83J\83E\83\93\83g
836                                          0,             //size
837                                          0,             //RoundDate
838                                          0,                             //LastModified
839                                          0,                             //Kokomade
840                                          0,                             //NewReceive
841                                          '0',                   //\96¢\8eg\97p
842                                          0,                             //UnRead
843                                          0,                             //ScrollTop
844                                          Rec.FCount,    //AllResCount
845                                          0,                             //NewResCount
846                                          0]             //AgeSage
847                                         );
848
849                                 sl.Add(s);
850                                 inc(cnt);
851                         end;
852                         sl.EndUpdate;
853                         sl.SaveToFile(FileName);
854                 finally
855                         sl.Free;
856                 end;
857         finally
858                 SubjectList.Free;
859         end;
860 end;
861
862 {!
863 \brief \83X\83\8c\83b\83h\83C\83\93\83f\83b\83N\83X(Thread.dat)\8f\91\82«\8d\9e\82Ý
864 \param Thread.dat \82ð\8dì\90¬\82·\82é\94Â
865 }
866 procedure TGikoSys.WriteThreadDat(Board: TBoard);
867 //const
868 //      Values: array[Boolean] of string = ('0', '1');
869 var
870         i: integer;
871         FileName: string;
872         sl: TStringList;
873         s: string;
874         TmpFileList: TStringList;
875 begin
876         if not Board.IsThreadDatRead then
877                 Exit;
878         FileName := Board.GetFolderIndexFileName;
879         ForceDirectoriesEx( ExtractFilePath( FileName ) );
880
881         sl := TStringList.Create;
882         TmpFileList := TStringList.Create;
883         TmpFileList.Sorted := true;
884         try
885         TmpFileList.BeginUpdate;
886                 GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.tmp', TmpFileList, false);
887         TmpFileList.EndUpdate;
888                 sl.BeginUpdate;
889                 sl.Add(FOLDER_INDEX_VERSION);
890
891                 // \83X\83\8c\94Ô\8d\86\95Û\91\82Ì\82½\82ß\83\\81[\83g
892                 Sort.SetSortNoFlag(true);
893                 Sort.SetSortOrder(true);
894                 Sort.SetSortIndex(0);
895                 //Sort.SortNonAcquiredCountFlag := GikoSys.Setting.NonAcquiredCount;
896                 Board.CustomSort(ThreadItemSortProc);
897
898                 for i := 0 to Board.Count - 1 do begin
899                         Board.Items[i].No := i + 1;
900                         s := Format('%x'#1'%s'#1'%s'#1'%x'#1'%x'#1'%x'#1'%x'#1'%x'#1'%x'#1 +
901                                                         '%s'#1'%x'#1'%x'#1'%x'#1'%x'#1'%x',
902                                         [Board.Items[i].No,                     //\94Ô\8d\86
903                                          Board.Items[i].FileName, //\83t\83@\83C\83\8b\96¼
904                      MojuUtils.Sanitize(Board.Items[i].Title),    //\83^\83C\83g\83\8b
905                                          Board.Items[i].Count,     //\83J\83E\83\93\83g
906                                          Board.Items[i].Size,             //size
907                                          DateTimeToInt(Board.Items[i].RoundDate),             //RoundDate
908                                          DateTimeToInt(Board.Items[i].LastModified),                            //LastModified
909                                          Board.Items[i].Kokomade,                               //Kokomade
910                                          Board.Items[i].NewReceive,                             //NewReceive
911                                          '0',                   //\96¢\8eg\97p
912                                          BoolToInt(Board.Items[i].UnRead),                              //UnRead
913                                          Board.Items[i].ScrollTop,                              //ScrollTop
914                                          Board.Items[i].AllResCount,    //AllResCount
915                                          Board.Items[i].NewResCount,                            //NewResCount
916                                          Ord(Board.Items[i].AgeSage)]             //AgeSage
917                                         );
918
919                         sl.Add(s);
920                 end;
921                 sl.EndUpdate;
922                 sl.SaveToFile(FileName);
923
924                 for i := 0 to TmpFileList.Count - 1 do begin
925                         DeleteFile(ExtractFilePath(Board.GetFolderIndexFileName) + TmpFileList[i]);
926                 end;
927
928         finally
929                 TmpFileList.Free;
930                 sl.Free;
931         end;
932 end;
933
934 {!
935 \brief Folder.idx \82ð 1 \8ds\89ð\8eß
936 \param Line Folder.idx \82ð\8d\\90¬\82·\82é 1 \8ds
937 \return \83X\83\8c\83b\83h\8fî\95ñ
938 }
939 function TGikoSys.ParseIndexLine(Line: string): TIndexRec;
940 begin
941         Result.FNo := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
942         Result.FFileName := MojuUtils.RemoveToken(Line, #1);
943         Result.FTitle := MojuUtils.UnSanitize(MojuUtils.RemoveToken(Line, #1));
944         Result.FCount := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
945         Result.FSize := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
946         Result.FRoundDate := IntToDateTime(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), ZERO_DATE));
947         Result.FLastModified := IntToDateTime(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), ZERO_DATE));
948         Result.FKokomade := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), -1);
949         Result.FNewReceive := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
950         RemoveToken(Line, #1);//9: ;    //\96¢\8eg\97p
951         Result.FUnRead := IntToBool(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0));
952         Result.FScrollTop := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
953         Result.FAllResCount := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
954         Result.FNewResCount := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
955         Result.FAgeSage := TGikoAgeSage(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0));
956
957 end;
958
959 {!
960 \brief \8ew\92è\83t\83H\83\8b\83_\93à\82Ì\8ew\92è\83t\83@\83C\83\8b\88ê\97\97\82ð\8eæ\93¾\82·\82é
961 \param Path      \8bN\93_\82Æ\82È\82é\83t\83H\83\8b\83_\83p\83X
962 \param Mask      \83t\83@\83C\83\8b\96¼\82Ì\83}\83X\83N
963 \param List      OUT:\8eæ\93¾\82³\82ê\82½\83t\83@\83C\83\8b\96¼\88ê\97\97\82ª\95Ô\82é
964 \param SubDir    \92\86\82Ì\83t\83H\83\8b\83_\82Ü\82Å\8dÄ\8bA\93I\82É\83\8a\83X\83g\82·\82é\8fê\8d\87\82Í True
965 \param IsPathAdd \83p\83X\95t\82«\82Å\83\8a\83X\83g\83A\83b\83v\82·\82é\8fê\8d\87\82Í True
966
967 Mask \82ð '*.txt' \82Ì\82æ\82¤\82É\8ew\92è\82·\82é\82±\82Æ\82Å\81A
968 \93Á\92è\82Ì\83t\83@\83C\83\8b\96¼\82â\93Á\92è\82Ì\8ag\92£\8eq\82É\8di\82Á\82½\83\8a\83X\83g\83A\83b\83v\82ª\89Â\94\\82Å\82·\81B
969
970 \par \97á:
971 \code
972 GetFileList('c:\', '*.txt', list, True, True);
973 \endcode
974 }
975 procedure TGikoSys.GetFileList(Path: string; Mask: string; var List: TStringList; SubDir: Boolean; IsPathAdd: Boolean);
976 var
977         rc: Integer;
978         SearchRec : TSearchRec;
979         s: string;
980 begin
981         Path := IncludeTrailingPathDelimiter(Path);
982         rc := FindFirst(Path + '*.*', faAnyfile, SearchRec);
983         try
984                 while rc = 0 do begin
985                         if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then begin
986                                 s := Path + SearchRec.Name;
987
988                                 if (SearchRec.Attr and faDirectory = 0) and (MatchesMask(s, Mask)) then
989                                                 if IsPathAdd then
990                                                         List.Add(s)
991                                                 else
992                                                         List.Add(SearchRec.Name);
993                                 if SubDir and (SearchRec.Attr and faDirectory > 0) then
994                                         GetFileList(s, Mask, List, True, IsPathAdd);
995                         end;
996                         rc := FindNext(SearchRec);
997                 end;
998         finally
999                 SysUtils.FindClose(SearchRec);
1000         end;
1001         List.Sort;
1002 end;
1003
1004 {!
1005 \breif \8ew\92è\83t\83H\83\8b\83_\93à\82Ì\8ew\92è\83t\83@\83C\83\8b\88ê\97\97\82ð\8eæ\93¾\82·\82é\81B
1006                          \83T\83u\83t\83H\83\8b\83_\82Í\8c\9f\8dõ\82µ\82È\82¢
1007 \param Path      \8bN\93_\82Æ\82È\82é\83t\83H\83\8b\83_\83p\83X
1008 \param Mask      \83t\83@\83C\83\8b\96¼\82Ì\83}\83X\83N
1009 \param List      OUT:\8eæ\93¾\82³\82ê\82½\83t\83@\83C\83\8b\96¼\88ê\97\97\82ª\95Ô\82é
1010 \param IsPathAdd \83p\83X\95t\82«\82Å\83\8a\83X\83g\83A\83b\83v\82·\82é\8fê\8d\87\82Í True
1011 \note \8dÄ\8bN\8ew\92è\89Â\94\\82È GetFileList() \82ª\82 \82é\82Ì\82Å\82±\82Ì\8aÖ\90\94\82Í\95s\97v?
1012 \par \97á
1013 \code
1014 GetFileList('c:\', '*.txt', list, True);
1015 \endcode
1016 }
1017 procedure TGikoSys.GetFileList(Path: string; Mask: string; var List: TStringList; IsPathAdd: Boolean);
1018 var
1019         rc: Integer;
1020         SearchRec : TSearchRec;
1021 begin
1022         Path := IncludeTrailingPathDelimiter(Path);
1023         rc := FindFirst(Path + Mask, faAnyfile, SearchRec);
1024         try
1025                 while rc = 0 do begin
1026                         if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then begin
1027                                 if (SearchRec.Attr and faDirectory = 0) then begin
1028                     if IsPathAdd then begin
1029                         List.Add(Path + SearchRec.Name)
1030                     end else begin
1031                         List.Add(SearchRec.Name);
1032                     end;
1033                 end;
1034                         end;
1035                         rc := FindNext(SearchRec);
1036                 end;
1037         finally
1038                 SysUtils.FindClose(SearchRec);
1039         end;
1040         List.Sort;
1041 end;
1042
1043 {!
1044 \brief \8ew\92è\83t\83H\83\8b\83_\93à\82Ì\83f\83B\83\8c\83N\83g\83\8a\88ê\97\97\82ð\8eæ\93¾\82·\82é
1045 \param Path      \8bN\93_\82Æ\82È\82é\83t\83H\83\8b\83_\83p\83X
1046 \param Mask      \83t\83H\83\8b\83_\96¼\82Ì\83}\83X\83N
1047 \param List      OUT:\8eæ\93¾\82³\82ê\82½\83t\83H\83\8b\83_\96¼\88ê\97\97\82ª\95Ô\82é
1048 \param SubDir    \92\86\82Ì\83t\83H\83\8b\83_\82Ü\82Å\8dÄ\8bA\93I\82É\83\8a\83X\83g\82·\82é\8fê\8d\87\82Í True
1049
1050 Mask \82ð '*.txt' \82Ì\82æ\82¤\82É\8ew\92è\82·\82é\82±\82Æ\82Å\81A
1051 \93Á\92è\82Ì\83t\83@\83C\83\8b\96¼\82â\93Á\92è\82Ì\8ag\92£\8eq\82É\8di\82Á\82½\83\8a\83X\83g\83A\83b\83v\82ª\89Â\94\\82Å\82·\81B
1052
1053 \par \97á:
1054 \code
1055 GetDirectoryList('c:\', '*.txt', list, True);
1056 \endcode
1057 }
1058 procedure TGikoSys.GetDirectoryList(Path: string; Mask: string; List: TStringList; SubDir: Boolean);
1059 var
1060         rc: Integer;
1061         SearchRec : TSearchRec;
1062         s: string;
1063 begin
1064         Path := IncludeTrailingPathDelimiter(Path);
1065         rc := FindFirst(Path + '*.*', faDirectory, SearchRec);
1066         try
1067                 while rc = 0 do begin
1068                         if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then begin
1069                                 s := Path + SearchRec.Name;
1070                                 //if (SearchRec.Attr and faDirectory > 0) then
1071                                 //      s := IncludeTrailingPathDelimiter(s)
1072
1073                                 if (SearchRec.Attr and faDirectory > 0) and (MatchesMask(s, Mask)) then
1074                                         List.Add( IncludeTrailingPathDelimiter( s ) );
1075                                 if SubDir and (SearchRec.Attr and faDirectory > 0) then
1076                                         GetDirectoryList(s, Mask, List, True);
1077                         end;
1078                         rc := FindNext(SearchRec);
1079                 end;
1080         finally
1081                 SysUtils.FindClose(SearchRec);
1082         end;
1083 end;
1084
1085
1086 {!
1087 \brief Subject.txt \88ê\8ds\82ð\89ð\8eß
1088 \param Line Subject.txt \82ð\8d\\90¬\82·\82é 1 \8ds
1089 \return     \83X\83\8c\83b\83h\8fî\95ñ
1090 }
1091 function TGikoSys.DivideSubject(Line: string): TSubjectRec;
1092 var
1093         i: integer;
1094         ws: WideString;
1095         Delim: string;
1096         LeftK: string;
1097         RightK: string;
1098 begin
1099         Result.FCount := 0;
1100
1101         if AnsiPos('<>', Line) = 0 then
1102                 Delim := ','
1103         else
1104                 Delim := '<>';
1105         Result.FFileName := RemoveToken(Line, Delim);
1106         Result.FTitle := Trim(RemoveToken(Line, Delim));
1107
1108         ws := Result.FTitle;
1109         if Copy(ws, Length(ws), 1) = ')' then begin
1110                 LeftK := '(';
1111                 RightK := ')';
1112         end else if Copy(ws, Length(ws)-1, 2) = '\81j' then begin
1113                 LeftK := '\81i';
1114                 RightK := '\81j';
1115         end else if Copy(ws, Length(ws), 1) = '>' then begin
1116                 LeftK := '<';
1117                 RightK := '>';
1118         end;
1119         for i := Length(ws) - 1 downto 1 do begin
1120                 if Copy(ws, i, Length(LeftK)) = LeftK then begin
1121                         Result.FTitle := TrimRight(Copy(ws, 1, i - 1));
1122                         ws := Copy(ws, i + Length(LeftK), Length(ws) - i - Length(RightK));
1123                         if IsNumeric(ws) then
1124                                 Result.FCount := StrToInt(ws);
1125                         //Delete(Result.FTitle, i, Length(LeftK) + Length(ws) + Length(RightK));
1126                         break;
1127                 end;
1128         end;
1129 end;
1130
1131 {!
1132 \brief URL\82©\82çBBSID\82ð\8eæ\93¾
1133 \param url BBSID \82ð\8eæ\93¾\82·\82é URL
1134 \return    BBSID
1135 }
1136 function TGikoSys.UrlToID(url: string): string;
1137 var
1138         i: integer;
1139 begin
1140         Result := '';
1141         url := Trim(url);
1142
1143         if url = '' then Exit;
1144         try
1145                 url := Copy(url, 0, Length(url) - 1);
1146                 for i := Length(url) downto 0 do begin
1147                         if url[i] = '/' then begin
1148                                 Result := Copy(url, i + 1, Length(url));
1149                                 Break;
1150                         end;
1151                 end;
1152         except
1153                 Result := '';
1154         end;
1155 end;
1156
1157 {!
1158 \brief URL\82©\82ç\8dÅ\8cã\82Ì\97v\91f\82ð\8dí\8f\9c
1159 \param url \89ð\8eß\82·\82é URL
1160 \return    \90Ø\82è\8eæ\82ç\82ê\82½\8cã\82Ì URL
1161
1162 URL \82©\82ç BBSID\88È\8aO\82Ì\95\94\95ª\82ð\8eæ\93¾\82·\82é\82Ì\82É\8eg\97p\82µ\82Ü\82·\81B
1163 }
1164 function TGikoSys.UrlToServer(url: string): string;
1165 var
1166         i: integer;
1167         wsURL: WideString;
1168 begin
1169         Result := '';
1170         wsURL := url;
1171         wsURL := Trim(wsURL);
1172
1173         if wsURL = '' then exit;
1174
1175         if Copy(wsURL, Length(wsURL), 1) = '/' then
1176                 wsURL := Copy(wsURL, 0, Length(wsURL) - 1);
1177
1178         for i := Length(wsURL) downto 0 do begin
1179                 if wsURL[i] = '/' then begin
1180                         Result := Copy(wsURL, 0, i);
1181                         break;
1182                 end;
1183         end;
1184 end;
1185
1186 {!
1187 \brief \83f\83B\83\8c\83N\83g\83\8a\82ª\91\8dÝ\82·\82é\82©\83`\83F\83b\83N
1188 \param Name \91\8dÝ\82ð\8am\94F\82·\82é\83t\83H\83\8b\83_\83p\83X
1189 \return     \83t\83H\83\8b\83_\82ª\91\8dÝ\82·\82é\82È\82ç True
1190 }
1191 function TGikoSys.DirectoryExistsEx(const Name: string): Boolean;
1192 var
1193         Code: Cardinal;
1194 begin
1195         Code := GetFileAttributes(PChar(Name));
1196         Result := (Code <> Cardinal(-1)) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
1197 end;
1198
1199 {!
1200 \brief \83f\83B\83\8c\83N\83g\83\8a\8dì\90¬\81i\95¡\90\94\8aK\91w\91Î\89\9e\81j
1201 \param Dir \8dì\90¬\82·\82é\83p\83X
1202 \return    \8dì\90¬\82É\90¬\8c÷\82µ\82½\8fê\8d\87\82Í True
1203 }
1204 function TGikoSys.ForceDirectoriesEx(Dir: string): Boolean;
1205 begin
1206         Result := True;
1207         if Length(Dir) = 0 then
1208                 raise Exception.Create('\83t\83H\83\8b\83_\82ª\8dì\90¬\8fo\97\88\82Ü\82¹\82ñ');
1209         Dir := ExcludeTrailingPathDelimiter(Dir);
1210         if (Length(Dir) < 3) or DirectoryExistsEx(Dir)
1211                 or (ExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
1212         Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
1213 end;
1214
1215 {!
1216 \brief \95\8e\9a\97ñ\82©\82ç\83g\81[\83N\83\93\82Ì\90Ø\82è\8fo\82µ\81i\8f\89\8aú\8f\88\97\9d\81j
1217                          FDelphi\82©\82ç\82Ì\83p\83N\83\8a
1218 \param s   \8c³\82É\82È\82é\83L\83\83\83\89\83N\83^
1219 \param sep \8bæ\90Ø\82è\82É\82È\82é\95\8e\9a\97ñ
1220 \param Rec OUT:\95\8e\9a\97ñ\91\96\8d¸\8fî\95ñ\82ª\95Ô\82é
1221 \return    \90Ø\82è\8fo\82µ\82½\83g\81[\83N\83\93
1222 \todo Split, RemoveToken, GetTokenIndex, NthField \8ds\82«
1223 }
1224 function TGikoSys.StrTokFirst(const s:string; const sep: TStrTokSeparator; var Rec: TStrTokRec): string;
1225 begin
1226         Rec.Str := s;
1227         Rec.Pos := 1;
1228         Result := StrTokNext(sep, Rec);
1229 end;
1230
1231 {!
1232 \brief \95\8e\9a\97ñ\82©\82ç\83g\81[\83N\83\93\82Ì\90Ø\82è\8fo\82µ
1233                          FDelphi\82©\82ç\82Ì\83p\83N\83\8a
1234 \param sep \8bæ\90Ø\82è\82É\82È\82é\83L\83\83\83\89\83N\83^
1235 \param Rec IN/OUT:StrTokFirst\82Å\8dì\90¬\82³\82ê\82½\95\8e\9a\97ñ\91\96\8d¸\8fî\95ñ
1236 \return    \90Ø\82è\8fo\82µ\82½\83g\81[\83N\83\93
1237 \todo Split, RemoveToken, GetTokenIndex, NthField \8ds\82«
1238 }
1239 function TGikoSys.StrTokNext(const sep: TStrTokSeparator; var Rec: TStrTokRec): string;
1240 var
1241         Len, I: Integer;
1242 begin
1243         with Rec do     begin
1244                 Len := Length(Str);
1245                 Result := '';
1246                 if Len >= Pos then begin
1247                         while (Pos <= Len) and (Str[Pos] in sep) do begin
1248                          Inc(Pos);
1249                         end;
1250                         I := Pos;
1251                         while (Pos<= Len) and not (Str[Pos] in sep) do begin
1252                                 if IsDBCSLeadByte(Byte(Str[Pos])) then begin
1253                                         Inc(Pos);
1254                                 end;
1255                                 Inc(Pos);
1256                         end;
1257                         Result := Copy(Str, I, Pos - I);
1258                         while (Pos <= Len) and (Str[Pos] in sep) do begin// \82±\82ê\82Í\82¨\8dD\82Ý
1259                                 Inc(Pos);
1260                         end;
1261                 end;
1262         end;
1263 end;
1264
1265 {!
1266 \brief \83t\83@\83C\83\8b\83T\83C\83Y\8eæ\93¾
1267 \param FileName \83t\83@\83C\83\8b\83T\83C\83Y\82ð\8eæ\93¾\82·\82é\83t\83@\83C\83\8b\83p\83X
1268 \return         \83t\83@\83C\83\8b\83T\83C\83Y(bytes)
1269 }
1270 function TGikoSys.GetFileSize(FileName : string): longint;
1271 var
1272         F : File;
1273 begin
1274         try
1275                 if not FileExists(FileName) then begin
1276                         Result := 0;
1277                         Exit;
1278                 end;
1279                 Assign(F, FileName);
1280                 Reset(F, 1);
1281                 Result := FileSize(F);
1282                 CloseFile(F);
1283         except
1284                 Result := 0;
1285         end;
1286 end;
1287
1288 {!
1289 \brief \83e\83L\83X\83g\83t\83@\83C\83\8b\82Ì\8ds\90\94\82ð\8eæ\93¾
1290 \param FileName \8ds\90\94\82ð\8eæ\93¾\82·\82é\83t\83@\83C\83\8b\83p\83X
1291 \return         \8ds\90\94
1292 \todo \83\81\83\82\83\8a\83}\83b\83v\83h\83t\83@\83C\83\8b\8ds\82«
1293 }
1294 function TGikoSys.GetFileLineCount(FileName : string): longint;
1295 var
1296         sl: TStringList;
1297 begin
1298         sl := TStringList.Create;
1299         try
1300                 try
1301                         sl.LoadFromFile(FileName);
1302                         Result := sl.Count;
1303                 except
1304                         Result := 0;
1305                 end;
1306         finally
1307                 sl.Free;
1308         end;
1309
1310 end;
1311
1312 {!
1313 \brief \83t\83@\83C\83\8b\82©\82ç\8ew\92è\8ds\82ð\8eæ\93¾
1314 \param FileName \83t\83@\83C\83\8b\82Ì\83p\83X
1315 \param Line     \8ew\92è\8ds
1316 \return         \8ew\92è\82³\82ê\82½ 1 \8ds
1317 \todo \83\81\83\82\83\8a\83}\83b\83v\83h\83t\83@\83C\83\8b\8ds\82«
1318 }
1319 function TGikoSys.ReadThreadFile(FileName: string; Line: Integer): string;
1320 var
1321         fileTmp : TStringList;
1322 begin
1323         Result := '';
1324         if FileExists(FileName) then begin
1325                 fileTmp := TStringList.Create;
1326                 try
1327                         try
1328                                 fileTmp.LoadFromFile( FileName );
1329                                 if ( Line       >= 1 ) and ( Line       < fileTmp.Count + 1 ) then begin
1330                                         Result := fileTmp.Strings[ Line-1 ];
1331                                 end;
1332                         except
1333                                 //on EFOpenError do Result := '';
1334                         end;
1335                 finally
1336                         fileTmp.Free;
1337                 end;
1338         end;
1339 end;
1340
1341 {!
1342 \brief \83V\83X\83e\83\80\83\81\83j\83\85\81[\83t\83H\83\93\83g\82Ì\91®\90«\82ð\8eæ\93¾
1343 \param Font OUT:\8eæ\93¾\82µ\82½\83t\83H\83\93\83g\91®\90«\82ª\95Ô\82é
1344 }
1345 procedure TGikoSys.MenuFont(Font: TFont);
1346 var
1347         lf: LOGFONT;
1348         nm: NONCLIENTMETRICS;
1349 begin
1350         nm.cbSize := sizeof(NONCLIENTMETRICS);
1351     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @nm, 0);
1352     lf := nm.lfMenuFont;
1353     Font.Name := lf.lfFaceName;
1354     Font.Height := lf.lfHeight;
1355     Font.Style := [];
1356     if lf.lfWeight >= 700 then
1357         Font.Style := Font.Style + [fsBold];
1358     if lf.lfItalic = 1 then
1359         Font.Style := Font.Style + [fsItalic];
1360 end;
1361
1362 {!
1363 \brief \90æ\93ª\82Ì\83g\81[\83N\83\93\82ð\90Ø\82è\8fo\82µ
1364 \param s         IN/OUT:\8c³\82É\82È\82é\95\8e\9a\97ñ\81A\90Ø\82è\8fo\82µ\82½\8cã\82Ì\8ec\82è\82Ì\95\8e\9a\97ñ
1365 \param delimiter \8bæ\90Ø\82è\82É\82È\82é\95\8e\9a\97ñ
1366 \return          \90Ø\82è\8fo\82µ\82½\95\8e\9a\97ñ
1367
1368 \82Ç\82±\82©\82Ì\83T\83C\83g\82©\82ç\82Ì\83p\83N\83\8a
1369 }
1370 function TGikoSys.RemoveToken(var s: string;const delimiter: string): string;
1371 var
1372         p: Integer;
1373 begin
1374         p := AnsiPos(delimiter, s);
1375         if p = 0 then
1376                 Result := s
1377         else
1378                 Result := Copy(s, 1, p - 1);
1379         Delete(s, 1, Length(Result) + Length(delimiter));
1380 end;
1381
1382
1383 {!
1384 \brief n \8cÂ\96Ú\82Ì\83g\81[\83N\83\93\82ð\90Ø\82è\8fo\82µ
1385 \param s     \8c³\82É\82È\82é\95\8e\9a\97ñ
1386 \param index 0 \82©\82ç\8en\82Ü\82é\83C\83\93\83f\83b\83N\83X(n \8cÂ\96Ú\82Ì n)
1387 \return \90Ø\82è\8fo\82µ\82½\83g\81[\83N\83\93
1388
1389 \82Ç\82±\82©\82Ì\83T\83C\83g\82©\82ç\82Ì\83p\83N\83\8a
1390 }
1391 function TGikoSys.GetTokenIndex(s: string; delimiter: string; index: Integer): string;
1392 var
1393         i: Integer;
1394 begin
1395         Result := '';
1396         for i := 0 to index do
1397                 Result := RemoveToken(s, delimiter);
1398 end;
1399
1400
1401 //\83C\83\93\83f\83b\83N\83X\96¢\8dX\90V\83o\83b\83t\83@\82ð\83t\83\89\83b\83V\83\85\81I
1402 {procedure TGikoSys.FlashExitWrite;
1403 var
1404         i: Integer;
1405 begin
1406         //\83X\83\8c\83b\83h\83f\81[\83^\83t\83@\83C\83\8b\82ð\8dX\90V
1407         for i := 0 to FExitWrite.Count - 1 do
1408                 WriteThreadDat(FExitWrite[i]);
1409         FExitWrite.Clear;
1410 end;}
1411
1412 {!
1413 \brief \83X\83\8c\96¼\82È\82Ç\82ð\92Z\82¢\96¼\91O\82É\95Ï\8a·\82·\82é
1414 \param LongName \8c³\82É\82È\82é\95\8e\9a\97ñ
1415 \param ALength  \8eû\82ß\82é\95\8e\9a\97ñ\92·(bytes)
1416 \return         \95Ï\8a·\82³\82ê\82½\95\8e\9a\97ñ
1417
1418 from HotZonu
1419 }
1420 function TGikoSys.GetShortName(const LongName: string; ALength: integer): string;
1421 const
1422         ERASECHAR : array [1..39] of string =
1423                 ('\81\99','\81\9a','\81¡','\81 ','\81\9f','\81\9e','\81Q','\81\94','\81£','\81¥',
1424                  '\81¢','\81¤','\81\9c','\81\9b','\81\9d','\81y','\81z','\81ô','\81s','\81t',
1425                  '\81g','\81h','\81k','\81l','\81e','\81f','\81\83','\81\84','\81á','\81â',
1426                  '\81o','\81p','\81q','\81r','\81w','\81x','\81¬','\81c', '\81@');
1427 var
1428         Chr : array [0..255]    of      char;
1429         S : string;
1430         i : integer;
1431 begin
1432         s := Trim(LongName);
1433         if (Length(s) <= ALength) then begin
1434                 Result := s;
1435         end else begin
1436                 S := s;
1437                 for i := Low(ERASECHAR) to      High(ERASECHAR) do      begin
1438                         S := CustomStringReplace(S, ERASECHAR[i], '');
1439                 end;
1440                 if (Length(S) <= ALength) then begin
1441                         Result := S;
1442                 end else begin
1443                         Windows.LCMapString(
1444                                         GetUserDefaultLCID(),
1445                                         LCMAP_HALFWIDTH,
1446                                         PChar(S),
1447                                         Length(S) + 1,
1448                                         chr,
1449                                         Sizeof(chr)
1450                                         );
1451                         S := Chr;
1452                         S := Copy(S,1,ALength);
1453                         while true do begin
1454                                 if (ByteType(S, Length(S)) = mbLeadByte ) then begin
1455                                         S := Copy(S, 1, Length(S) - 1);
1456                                 end else begin
1457                                         Break;
1458                                 end;
1459                         end;
1460                         Result := S;
1461                 end;
1462         end;
1463 end;
1464
1465 {!
1466 \brief Boolean \82ð Integer \82É\95Ï\8a·
1467 \return False..0, True..1
1468 }
1469 function TGikoSys.BoolToInt(b: Boolean): Integer;
1470 begin
1471         Result := IfThen(b, 1, 0);
1472 end;
1473
1474 {!
1475 \brief Integer \82ð Boolean \82É\95Ï\8a·
1476 \return 1..True, other..False
1477 \todo 0..False, other..True \82Ì\95û\82ª\82¢\82¢\82Ì\82Å\82Í?
1478                         (\82±\82Ì\8ed\97l\82É\88Ë\91\82µ\82Ä\82¢\82é\82©\82à\82µ\82ê\82È\82¢\82Ì\82Å\96¢\8fC\90³)
1479 }
1480 function TGikoSys.IntToBool(i: Integer): Boolean;
1481 begin
1482         Result := i = 1;
1483 end;
1484
1485 {!
1486 \brief gzip\82Å\88³\8fk\82³\82ê\82½\82Ì\82ð\96ß\82·
1487 \param ResStream       \93Ç\82Ý\8d\9e\82Þ\83X\83g\83\8a\81[\83\80
1488 \param ContentEncoding \83G\83\93\83R\81[\83f\83B\83\93\83O
1489 \return                \93W\8aJ\82³\82ê\82½\95\8e\9a\97ñ
1490 }
1491 function TGikoSys.GzipDecompress(ResStream: TStream; ContentEncoding: string): string;
1492 const
1493         BUF_SIZE = 4096;
1494 var
1495         GZipStream: TGzipDecompressStream;
1496         TextStream: TStringStream;
1497         buf: array[0..BUF_SIZE - 1] of Byte;
1498         cnt: Integer;
1499         s: string;
1500         i, ln: Integer;
1501 begin
1502         Result := '';
1503         TextStream := TStringStream.Create('');
1504         try
1505 //\83m\81[\83g\83\93\83E\83\93\83`\83E\83B\83\8b\83X2003\91Î\8dô(x-gzip\82Æ\82©\82É\82È\82é\82Ý\82½\82¢)
1506 //              if LowerCase(Trim(ContentEncoding)) = 'gzip' then begin
1507                 if AnsiPos('gzip', LowerCase(Trim(ContentEncoding))) > 0 then begin
1508                         ResStream.Position := 0;
1509                         GZipStream := TGzipDecompressStream.Create(TextStream);
1510                         try
1511                                 repeat
1512                                         FillChar(buf, BUF_SIZE, 0);
1513                                         cnt := ResStream.Read(buf, BUF_SIZE);
1514                                         if cnt > 0 then
1515                                                 GZipStream.Write(buf, BUF_SIZE);
1516                                 until cnt = 0;
1517                         finally
1518                                 GZipStream.Free;
1519                         end;
1520                 end else begin
1521                         ResStream.Position := 0;
1522                         repeat
1523                                 FillChar(buf, BUF_SIZE, 0);
1524                                 cnt := ResStream.Read(buf, BUF_SIZE);
1525                                 if cnt > 0 then
1526                                         TextStream.Write(buf, BUF_SIZE);
1527                         until cnt = 0;
1528                 end;
1529
1530                 //NULL\95\8e\9a\82ð"*"\82É\82·\82é
1531                 s := TextStream.DataString;
1532                 i := Length(s);
1533                 ln := i;
1534                 while (i > 0) and (s[i] = #0) do
1535                         Dec(i);
1536                 Delete(s, i + 1, ln - i);
1537
1538                 i := Pos(#0, s);
1539                 while i <> 0 do begin
1540                         s[i] := '*';
1541                         i := Pos(#0, s);
1542                 end;
1543
1544                 Result := s;
1545         finally
1546                 TextStream.Free;
1547         end;
1548 end;
1549
1550 {!
1551 \brief \83A\83N\83V\83\87\83\93\82É\83V\83\87\81[\83g\83J\83b\83g\83L\81[\82ð\90Ý\92è
1552 \param ActionList \90Ý\92è\82·\82é\83A\83N\83V\83\87\83\93\88ê\97\97
1553 \param FileName Ini\83t\83@\83C\83\8b\82Ì\96¼\91O
1554 }
1555 procedure TGikoSys.LoadKeySetting(ActionList: TActionList; FileName: String);
1556 const
1557         STD_SEC = 'KeySetting';
1558 var
1559         i: Integer;
1560         ini: TMemIniFile;
1561         ActionName: string;
1562         ActionKey: Integer;
1563         SecList: TStringList;
1564         Component: TComponent;
1565 begin
1566         if not FileExists(fileName) then
1567                 Exit;
1568         SecList := TStringList.Create;
1569         ini := TMemIniFile.Create(fileName);
1570         try
1571                 ini.ReadSection(STD_SEC, SecList);
1572                 for i := 0 to SecList.Count - 1 do begin
1573                         ActionName := SecList[i];
1574                         ActionKey := ini.ReadInteger(STD_SEC, ActionName, -1);
1575                         if ActionKey <> -1 then begin
1576                                 Component := ActionList.Owner.FindComponent(ActionName);
1577                                 if TObject(Component) is TAction then begin
1578                                         TAction(Component).ShortCut := ActionKey;
1579                                 end;
1580                         end;
1581                 end;
1582         finally
1583                 ini.Free;
1584                 SecList.Free;
1585         end;
1586 end;
1587
1588 {!
1589 \brief \83A\83N\83V\83\87\83\93\82É\90Ý\92è\82³\82ê\82Ä\82¢\82é\83V\83\87\81[\83g\83J\83b\83g\83L\81[\82ð\83t\83@\83C\83\8b\82É\95Û\91
1590 \param ActionList \95Û\91\82·\82é\83A\83N\83V\83\87\83\93\88ê\97\97
1591 \param FileName Ini\83t\83@\83C\83\8b\96¼
1592
1593 ActionList \82É\90Ý\92è\82³\82ê\82Ä\82¢\82é\83V\83\87\81[\83g\83J\83b\83g\83L\81[\82ð FileName \82É\95Û\91\82µ\82Ü\82·\81B
1594 }
1595 procedure TGikoSys.SaveKeySetting(ActionList: TActionList; FileName: String);
1596 const
1597         STD_SEC = 'KeySetting';
1598 var
1599         i: Integer;
1600         ini: TMemIniFile;
1601 begin
1602         ini := TMemIniFile.Create(GetConfigDir + FileName);
1603         try
1604                 for i := 0 to ActionList.ActionCount - 1 do begin
1605                         if ActionList.Actions[i].Tag = -1 then
1606                                 Continue;
1607                         ini.WriteInteger(STD_SEC, ActionList.Actions[i].Name, TAction(ActionList.Actions[i]).ShortCut);
1608                 end;
1609                 ini.UpdateFile;
1610         finally
1611                 ini.Free;
1612         end;
1613 end;
1614
1615
1616 {!
1617 \brief \83v\83\8d\83Z\83X\82Ì\90\90¬
1618 \param AppPath \8bN\93®\82·\82é\83v\83\8d\83Z\83X\82Ì\83t\83@\83C\83\8b\83p\83X
1619 \param Param   AppPath \82É\93n\82·\88ø\90\94
1620 }
1621 procedure TGikoSys.CreateProcess(const AppPath: string; const Param: string);
1622 var
1623         PI: TProcessInformation;
1624         SI: TStartupInfo;
1625         Path: string;
1626 begin
1627         Path := '"' + AppPath + '"';
1628         if Param <> '' then
1629                 Path := Path + ' ' + Param;
1630
1631         SI.Cb := SizeOf(Si);
1632         SI.lpReserved   := nil;
1633         SI.lpDesktop     := nil;
1634         SI.lpTitle               := nil;
1635         SI.dwFlags               := 0;
1636         SI.cbReserved2 := 0;
1637         SI.lpReserved2 := nil;
1638         SI.dwysize               := 0;
1639         Windows.CreateProcess(nil,
1640                                                                 PChar(Path),
1641                                                                 nil,
1642                                                                 nil,
1643                                                                 False,
1644                                                                 0,
1645                                                                 nil,
1646                                                                 nil,
1647                                                                 SI,
1648                                                                 PI);
1649 end;
1650
1651 {!
1652 \brief Web \83u\83\89\83E\83U\82ð\8bN\93®
1653 \param URL         Web \83u\83\89\83E\83U\82Å\95\\8e¦\82·\82é URL
1654 \param BrowserType \83u\83\89\83E\83U\82Ì\83^\83C\83v(IE \82©\82Ç\82¤\82©)
1655 }
1656 procedure TGikoSys.OpenBrowser(URL: string; BrowserType: TGikoBrowserType);
1657 begin
1658         case BrowserType of
1659                 gbtIE:
1660                         HlinkNavigateString(nil, PWideChar(WideString(URL)));
1661                 gbtUserApp, gbtAuto:
1662                         if (Setting.URLApp) and (FileExists(Setting.URLAppFile)) then
1663                                 GikoSys.CreateProcess(Setting.URLAppFile, URL)
1664                         else
1665                                 HlinkNavigateString(nil, PWideChar(WideString(URL)));
1666         end;
1667 end;
1668
1669 {!
1670 \brief \95\8e\9a\8eÀ\91Ì\8eQ\8fÆ\82ð\83f\83R\81[\83h
1671 \param AStr \83f\83R\81[\83h\82·\82é\95\8e\9a\97ñ
1672 \return     \83f\83R\81[\83h\82³\82ê\82½\95\8e\9a\97ñ
1673 }
1674 function TGikoSys.HTMLDecode(const AStr: String): String;
1675 var
1676         Sp, Rp, Cp, Tp: PChar;
1677         S: String;
1678         I, Code: Integer;
1679         Num: Boolean;
1680 begin
1681         SetLength(Result, Length(AStr));
1682         Sp := PChar(AStr);
1683         Rp := PChar(Result);
1684         //Cp := Sp;
1685         try
1686                 while Sp^ <> #0 do begin
1687                         case Sp^ of
1688                                 '&': begin
1689                                                          //Cp := Sp;
1690                                                          Inc(Sp);
1691                                                          case Sp^ of
1692                                                                  'a': if AnsiStrPos(Sp, 'amp;') = Sp then
1693                                                                                         begin
1694                                                                                                 Inc(Sp, 3);
1695                                                                                                 Rp^ := '&';
1696                                                                                         end;
1697                                                                  'l',
1698                                                                  'g': if (AnsiStrPos(Sp, 'lt;') = Sp) or (AnsiStrPos(Sp, 'gt;') = Sp) then
1699                                                                                         begin
1700                                                                                                 Cp := Sp;
1701                                                                                                 Inc(Sp, 2);
1702                                                                                                 while (Sp^ <> ';') and (Sp^ <> #0) do
1703                                                                                                         Inc(Sp);
1704                                                                                                 if Cp^ = 'l' then
1705                                                                                                         Rp^ := '<'
1706                                                                                                 else
1707                                                                                                         Rp^ := '>';
1708                                                                                         end;
1709                                                                  'q': if AnsiStrPos(Sp, 'quot;') = Sp then
1710                                                                                         begin
1711                                                                                                 Inc(Sp,4);
1712                                                                                                 Rp^ := '"';
1713                                                                                         end;
1714                                                                  '#': begin
1715                                                                                                 Tp := Sp;
1716                                                                                                 Inc(Tp);
1717                                                                                                 Num := IsNumeric(Copy(Tp, 1, 1));
1718                                                                                                 while (Sp^ <> ';') and (Sp^ <> #0) do begin
1719                                                                                                         if (Num) and (not IsNumeric(Copy(Sp, 1, 1))) then
1720                                                                                                                 Break;
1721                                                                                                         Inc(Sp);
1722                                                                                                 end;
1723                                                                                                 SetString(S, Tp, Sp - Tp);
1724                                                                                                 Val(S, I, Code);
1725                                                                                                 Rp^ := Chr((I));
1726                                                                                         end;
1727                                                          //      else
1728                                                                          //raise EConvertError.CreateFmt(sInvalidHTMLEncodedChar,
1729                                                                                  //[Cp^ + Sp^, Cp - PChar(AStr)])
1730                                                          end;
1731                                          end
1732                         else
1733                                 Rp^ := Sp^;
1734                         end;
1735                         Inc(Rp);
1736                         Inc(Sp);
1737                 end;
1738         except
1739 //              on E:EConvertError do
1740 //                      raise EConvertError.CreateFmt(sInvalidHTMLEncodedChar,
1741 //                              [Cp^ + Sp^, Cp - PChar(AStr)])
1742         end;
1743         SetLength(Result, Rp - PChar(Result));
1744 end;
1745
1746 {!
1747 \brief HTML \82Ì\83A\83\93\83J\81[\83^\83O\82©\82ç URL \82ð\8eæ\93¾
1748 \param s URL \82ð\8eæ\93¾\82·\82é HTML
1749 \return  \8eæ\93¾\82µ\82½ URL
1750 }
1751 function TGikoSys.GetHRefText(s: string): string;
1752 var
1753         Index: Integer;
1754         Index2: Integer;
1755 begin
1756         Result := '';
1757         s := Trim(s);
1758         if s = '' then
1759                 Exit;
1760
1761         Index := AnsiPos('href', LowerCase(s));
1762         if Index = 0 then
1763                 Exit;
1764         s := Trim(Copy(s, Index + 4, Length(s)));
1765         s := Trim(Copy(s, 2, Length(s)));
1766
1767         //\8en\82ß\82Ì\95\8e\9a\82ª'"'\82È\82ç\8eæ\82è\8f\9c\82­
1768         //if Copy(s, 1, 1) = '"' then begin
1769     if s[1]  = '"' then begin
1770                 s := Trim(Copy(s, 2, Length(s)));
1771         end;
1772
1773         Index := AnsiPos('"', s);
1774         if Index <> 0 then begin
1775                 //'"'\82Ü\82ÅURL\82Æ\82·\82é
1776                 s := Copy(s, 1, Index - 1);
1777         end else begin
1778                 //'"'\82ª\96³\82¯\82ê\82Î\83X\83y\81[\83X\82©">"\82Ì\91\81\82¢\95û\82Ü\82Å\82ðURL\82Æ\82·\82é
1779                 Index := AnsiPos(' ', s);
1780                 Index2 := AnsiPos('>', s);
1781                 if Index = 0 then
1782                         Index := Index2;
1783                 if Index > Index2 then
1784                         Index := Index2;
1785                 if Index <> 0 then
1786                         s := Copy(s, 1, Index - 1)
1787                 else
1788                         //\82±\82ê\88È\8fã\82à\82¤\92m\82ç\82ñ\82Ê
1789                         ;
1790         end;
1791         Result := Trim(s);
1792 end;
1793
1794 {!
1795 \brief \83z\83X\83g\96¼\82ª\82Q\82\83\82\88\82©\82Ç\82¤\82©\83`\83F\83b\83N\82·\82é
1796 \param Host \83`\83F\83b\83N\82·\82é\83z\83X\83g\96¼
1797 \return     2\82¿\82á\82ñ\82Ë\82é\82Ì\83z\83X\83g\96¼\82È\82ç True
1798 }
1799 function TGikoSys.Is2chHost(Host: string): Boolean;
1800 const
1801         HOST_NAME: array[0..1] of string = ('2ch.net', 'bbspink.com');
1802 var
1803         i: Integer;
1804 //      Len: Integer;
1805 begin
1806         Result := False;
1807         if RightStr( Host, 1 ) = '/' then
1808                 Host := Copy( Host, 1, Length( Host ) - 1 );
1809         OutputDebugString(pchar(HOST_NAME[0]));
1810         for i := 0 to Length(HOST_NAME) - 1 do begin
1811 //              Len := Length(HOST_NAME[i]);
1812                 if (AnsiPos(HOST_NAME[i], Host) > 0) and
1813                         (AnsiPos(HOST_NAME[i], Host) = (Length(Host) - Length(HOST_NAME[i]) + 1)) then begin
1814                         Result := True;
1815                         Exit;
1816                 end;
1817         end;
1818 end;
1819
1820 {!
1821 \brief 2\82¿\82á\82ñ\82Ë\82é\8c`\8e®\82Ì URL \82ð\95ª\89ð
1822 \param url      2\82¿\82á\82ñ\82Ë\82é\8c`\8e®\82Ì URL
1823 \param path     test/read.cgi \82È\82Ç\82Ì\92\86\8aÔ\83p\83X(ParseURI \82©\82ç\93¾\82é)
1824 \param document index.html \82È\82Ç\82Ì\83h\83L\83\85\83\81\83\93\83g\96¼(ParseURI \82©\82ç\93¾\82é)
1825 \param BBSID    OUT:BBSID \82ª\95Ô\82é(ex. giko)
1826 \param BBSKey   OUT:\83X\83\8c\83b\83h\83L\81[\82ª\95Ô\82é(ex. 10000000000)
1827 \return 2\82¿\82á\82ñ\82Ë\82é\82Ì URL \82Æ\82µ\82Ä\95ª\89ð\82Å\82«\82½\82È\82ç True
1828 }
1829 function TGikoSys.Parse2chURL(const url: string; const path: string; const document: string; var BBSID: string; var BBSKey: string): Boolean;
1830 var
1831         Index: Integer;
1832         s: string;
1833         SList: TStringList;
1834 begin
1835         BBSID := '';
1836         BBSKey := '';
1837         Result := False;
1838
1839         Index := AnsiPos(READ_PATH, path);
1840         if Index <> 0 then begin
1841                 s := Copy(path, Index + Length(READ_PATH), Length(path));
1842     end else begin
1843         Index := AnsiPos(HTML_READ_PATH, path);
1844         if Index <> 0 then begin
1845             s := Copy(path, Index + Length(HTML_READ_PATH), Length(path));
1846         end;
1847     end;
1848     if Index <> 0 then begin
1849                 if (Length(s) > 0) and (s[1] = '/') then
1850                         Delete(s, 1, 1);
1851                 BBSID := GetTokenIndex(s, '/', 0);
1852                 BBSKey := GetTokenIndex(s, '/', 1);
1853                 if BBSKey = '' then
1854                         BBSKey := Document;
1855                 Result := (BBSID <> '') or (BBSKey <> '');
1856                 Exit;
1857         end;
1858         Index := AnsiPos(KAKO_PATH, path);
1859         if Index <> 0 then begin
1860                 s := Copy(path, 2, Length(path));
1861                 BBSID := GetTokenIndex(s, '/', 0);
1862                 if (BBSID = 'log') and (GetTokenIndex(s, '/', 2) = 'kako') then
1863                         BBSID := GetTokenIndex(s, '/', 1);
1864                 BBSKey := ChangeFileExt(Document, '');
1865                 Result := (BBSID <> '') or (BBSKey <> '');
1866                 Exit;
1867         end;
1868         Index := AnsiPos('read.cgi?', URL);
1869         if Index <> 0 then begin
1870                 SList := TStringList.Create;
1871                 try
1872                         try
1873 //                              s := HTMLDecode(Document);
1874                                 ExtractHTTPFields(['?', '&'], [], PChar(URL), SList, False);
1875                                 BBSID := SList.Values['bbs'];
1876                                 BBSKey := SList.Values['key'];
1877                                 Result := (BBSID <> '') or (BBSKey <> '');
1878                                 Exit;
1879                         except
1880                                 Exit;
1881                         end;
1882                 finally
1883                         SList.Free;
1884                 end;
1885         end;
1886 end;
1887
1888 {!
1889 \brief 2ch \8c`\8e®\82Ì URL \82©\82ç\83\8c\83X\94Ô\82ð\8eæ\93¾
1890 \param URL    2\82¿\82á\82ñ\82Ë\82é\8c`\8e®\82Ì URL
1891 \param stRes  OUT:\8aJ\8en\83\8c\83X\94Ô\82ª\95Ô\82é
1892 \param endRes OUT:\8fI\97¹\83\8c\83X\94Ô\82ª\95Ô\82é
1893
1894 http://2ch.net/\92\86\97ª/32-50 \n
1895 \82Ì\8fê\8d\87 stRef = 32, endRes = 50 \82É\82È\82é
1896 }
1897 procedure TGikoSys.GetPopupResNumber(URL : string; var stRes, endRes : Int64);
1898 var
1899         buf : String;
1900         convBuf : String;
1901         ps : Int64;
1902         pch : PChar;
1903 begin
1904         URL := Trim(LowerCase(URL));
1905         if (AnsiPos('&st=', URL ) <> 0) and ( AnsiPos( '&to=',URL) <> 0 ) then begin
1906                 stRes := 0;
1907                 endRes := 0;
1908                 try
1909                         buf := Copy( URL, AnsiPos('&st=', URL ) + 4, AnsiPos( '&to=',URL) - AnsiPos('&st=', URL ) - 4 );
1910                         if buf <> '' then
1911                                 stRes := StrToInt64( buf );
1912                         if AnsiPos( '&nofirst=',URL) <> 0 then begin
1913                                 buf := Copy( URL, AnsiPos('&to=', URL ) + 4, AnsiPos( '&nofirst=',URL) - AnsiPos('&to=', URL ) - 4);
1914                         end else begin
1915                                 buf := Copy( URL, AnsiPos('&to=', URL ) + 4, Length( URL ) - AnsiPos('&to=', URL ) - 4 + 1 );
1916                                 ps := 0;
1917                                 pch := PChar(buf);
1918                                 while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
1919                                 buf := Copy( buf, 1, ps );
1920                         end;
1921                         try
1922                                 if buf <> '' then
1923                                         endRes := StrToInt64(buf)
1924                         except
1925                                 endRes := 0;
1926                         end;
1927                 except
1928                         stRes := 0;
1929                 end;
1930                 if (stRes <> 0) and (endRes = 0) then
1931                         endRes := stRes + MAX_POPUP_RES
1932                 else if (stRes = 0) and (endRes <> 0) then begin
1933                         stRes := endRes - MAX_POPUP_RES;
1934                         if stRes < 1 then
1935                                 stRes := 1;
1936                 end;
1937                 GikoSys.GetBrowsableThreadURL( URL );
1938         end else if( AnsiPos('&res=', URL ) <> 0 ) then begin
1939                 endRes := 0;
1940                 buf := Copy( URL, AnsiPos('&res=', URL ) + 5, Length( URL ) - AnsiPos('&res=', URL ) - 5 + 1 );
1941                 ps := 0;
1942                 pch := PChar(buf);
1943                 while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
1944                 buf := Copy( buf, 1, ps );
1945                 try
1946                         if buf <> '' then
1947                                 stRes := StrToInt(buf)
1948                         else begin
1949                                 stRes := 0;
1950                         end;
1951                 except
1952                         stRes := 0;
1953                 end;
1954         end else if (AnsiPos('&start=', URL ) <> 0) and ( AnsiPos( '&end=',URL) <> 0 ) then begin
1955                 try
1956                         stRes := StrToInt64( Copy( URL, AnsiPos('&start=', URL ) + 7, AnsiPos( '&end=',URL) - AnsiPos('&start=', URL ) - 7 ) );
1957                         if AnsiPos( '&nofirst=',URL) <> 0 then begin
1958                                 buf := Copy( URL, AnsiPos('&end=', URL ) + 5, AnsiPos( '&nofirst=',URL) - AnsiPos('&end=', URL ) - 5);
1959                         end else begin
1960                                 buf := Copy( URL, AnsiPos('&end=', URL ) + 5, Length( URL ) - AnsiPos('&to=', URL ) - 5 + 1 );
1961                                 ps := 0;
1962                                 pch := PChar(buf);
1963                                 while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
1964                                 buf := Copy( buf, 1, ps );
1965                         end;
1966                         try
1967                                 if buf <> '' then
1968                                         endRes := StrToInt64(buf);
1969                         except
1970                                 endRes := 0;
1971                         end;
1972                 except
1973                         stRes := 0;
1974                 end;
1975         end else if ( AnsiPos('.html',URL) <> Length(URL) -4 ) and ( AnsiPos('.htm',URL) <> Length(URL) -3 ) then begin
1976                 buf := Copy(URL, LastDelimiter('/',URL)+1,Length(URL)-LastDelimiter('/',URL)+1);
1977                 if  Length(buf) > 0 then begin
1978                         if AnsiPos('-', buf) = 1 then begin
1979                                 stRes := 0;
1980                                 Delete(buf,1,1);
1981                                 ps := 0;
1982                                 pch := PChar(buf);
1983                                 while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
1984                                 try
1985                                         convBuf := Copy( buf, 1, ps );
1986                                         if convBuf <> '' then
1987                                                 endRes := StrToInt64(convBuf)
1988                                         else
1989                                                 endRes := 0;
1990                                 except
1991                                         endRes := 0;
1992                                 end;
1993                                 if endRes <> 0 then begin
1994                                         stRes := endRes - MAX_POPUP_RES;
1995                                         if stRes < 1 then
1996                                                 stRes := 1;
1997                                 end;
1998                         end else begin
1999                                 ps := 0;
2000                                 pch := PChar(buf);
2001                                 while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
2002                                 try
2003                                         convBuf := Copy( buf, 1, ps );
2004                                         if convBuf <> '' then begin
2005                                                 stRes := StrToInt64(convBuf);
2006                                                 Delete(buf,1,ps+1);
2007                                                 ps := 0;
2008                                                 pch := PChar(buf);
2009                                                 while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
2010                                                 try
2011                                                         convBuf := Copy( buf, 1, ps );
2012                                                         if convBuf <> '' then
2013                                                                 endRes := StrToInt64(convBuf)
2014                                                         else
2015                                                                 endRes := 0;
2016                                                 except
2017                                                         endRes := 0;
2018                                                 end;
2019                                         end else begin
2020                                                 stRes := 0;
2021                                         end;
2022                                 except
2023                                         stRes := 0;
2024                                         endRes := 0;
2025                                 end;
2026                         end;
2027                 end;
2028         end else begin
2029                 //stRes := 0;
2030                 //endRes := 0;
2031         end;
2032 end;
2033
2034 {!
2035 \brief 2\82¿\82á\82ñ\82Ë\82é\8c`\8e®\82Ì URL \82ð\95ª\89ð
2036 \param URL 2\82¿\82á\82ñ\82Ë\82é\8c`\8e®\82Ì URL
2037 \return    \95ª\89ð\82³\82ê\82½\97v\91f
2038 }
2039 function TGikoSys.Parse2chURL2(URL: string): TPathRec;
2040 var
2041         i: Integer;
2042         s: string;
2043 //      buf : String;
2044 //      convBuf : String;
2045         wk: string;
2046         wkMin: Integer;
2047         wkMax: Integer;
2048         wkInt: Integer;
2049         RStart: Integer;
2050         RLength: Integer;
2051 //      ps : Integer;
2052 //      pch : PChar;
2053         SList: TStringList;
2054 begin
2055         URL := Trim(LowerCase(URL));
2056         Result.FBBS := '';
2057         Result.FKey := '';
2058         Result.FSt := 0;
2059         Result.FTo := 0;
2060         Result.FFirst := False;
2061         Result.FStBegin := False;
2062         Result.FToEnd := False;
2063         Result.FDone := False;
2064         Result.FNoParam := False;
2065
2066         wkMin := 0;
2067         wkMax := 1;
2068         if URL[length(URL)] = '\' then
2069                 URL := URL + 'n';
2070         FAWKStr.RegExp := 'http://.+\.(2ch\.net|bbspink\.com)/';
2071         if FAWKStr.Match(FAWKStr.ProcessEscSeq(URL), RStart, RLength) <> 0 then begin
2072                 s := Copy(URL, RStart + RLength - 1, Length(URL));
2073
2074                 //\95W\8f\80\8f\91\8e®
2075                 //\8dÅ\8cã\82Íl50, 10, 10-20, 10n, 10-20n, -10, 10-, 10n- \82È\82Ç
2076                 //http://xxx.2ch.net/test/read.cgi/bbsid/1000000000/
2077                 FAWKStr.RegExp := '/test/read.(cgi|html)/.+/[0-9]+/?.*';
2078                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2079                         s := Copy(s, 15, Length(s));
2080
2081                         SList := TStringList.Create;
2082                         try
2083                                 SList.Clear;
2084                                 FAWKStr.RegExp := '/';
2085                                 if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 3 then begin
2086                                         Result.FBBS := SList[1];
2087                                         Result.FKey := SList[2];
2088                                         if SList.Count >= 4 then
2089                                                 s := SList[3]
2090                                         else begin
2091                                                 s := '';
2092                                                 Result.FNoParam := true;
2093                                         end;
2094                                 end else
2095                                         Exit;
2096
2097                                 SList.Clear;
2098                                 FAWKStr.LineSeparator := mcls_CRLF;
2099                                 FAWKStr.RegExp := '-';
2100                                 if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) = 0 then begin
2101                                         Result.FFirst := True;
2102                                 end else begin
2103                                         FAWKStr.RegExp := 'l[0-9]+';
2104                                         if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2105                                                 Result.FFirst := True;
2106                                         end else begin
2107                                                 for i := 0 to SList.Count - 1 do begin
2108                                                         if Trim(SList[i]) = '' then begin
2109                                                                 if i = 0 then
2110                                                                         Result.FStBegin := True;
2111                                                                 if i = (SList.Count - 1) then
2112                                                                         Result.FToEnd := True;
2113                                                         end else if IsNumeric(SList[i]) then begin
2114                                                                 wkInt := StrToInt(SList[i]);
2115                                                                 wkMax := Max(wkMax, wkInt);
2116                                                                 if wkMin = 0 then
2117                                                                         wkMin := wkInt
2118                                                                 else
2119                                                                         wkMin := Min(wkMin, wkInt);
2120                                                         end else if Trim(SList[i]) = 'n' then begin
2121                                                                 Result.FFirst := True;
2122                                                         end else begin
2123                                                                 FAWKStr.RegExp := '^n[0-9]+$|^[0-9]+n$';
2124                                                                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(SList[i]), RStart, RLength) > 0 then begin
2125                                                                         if Copy(SList[i], 1, 1) = 'n' then
2126                                                                                 wkInt := StrToInt(Copy(SList[i], 2, Length(SList[i])))
2127                                                                         else
2128                                                                                 wkInt := StrToInt(Copy(SList[i], 1, Length(SList[i]) - 1));
2129                                                                         Result.FFirst := True;
2130                                                                         wkMax := Max(wkMax, wkInt);
2131                                                                         if wkMin = 1 then
2132                                                                                 wkMin := wkInt
2133                                                                         else
2134                                                                                 wkMin := Min(wkMin, wkInt);
2135                                                                 end;
2136                                                         end;
2137                                                 end;
2138                                                 if Result.FStBegin and (not Result.FToEnd) then
2139                                                         Result.FSt := wkMin
2140                                                 else if (not Result.FStBegin) and Result.FToEnd then
2141                                                         Result.FTo := wkMax
2142                                                 else if (not Result.FStBegin) and (not Result.FToEnd) then begin
2143                                                         Result.FSt := wkMin;
2144                                                         Result.FTo := wkMax;
2145                                                 end;
2146                                                 //Result.FSt := wkMin;
2147                                                 //Result.FTo := wkMax;
2148                                         end;
2149                                 end;
2150                         finally
2151                                 SList.Free;
2152                         end;
2153                         Result.FDone := True;
2154                         Exit;
2155                 end;
2156
2157                 //\90Vkako\8f\91\8e®
2158                 //http://server.2ch.net/ITA_NAME/kako/1000/10000/1000000000.html
2159                 FAWKStr.RegExp := '/.+/kako/[0-9]+/[0-9]+/[0-9]+\.html';
2160                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2161                         SList := TStringList.Create;
2162                         try
2163                                 SList.Clear;
2164                                 FAWKStr.RegExp := '/';
2165                                 if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 6 then begin
2166                                         Result.FBBS := SList[1];
2167                                         Result.FKey := ChangeFileExt(SList[5], '');
2168                                         Result.FFirst := True;
2169                                 end else
2170                                         Exit;
2171                         finally
2172                                 SList.Free;
2173                         end;
2174                         Result.FDone := True;
2175                         Exit;
2176                 end;
2177
2178                 //\8b\8ckako\8f\91\8e®
2179                 //http://server.2ch.net/ITA_NAME/kako/999/999999999.html
2180                 FAWKStr.RegExp := '/.+/kako/[0-9]+/[0-9]+\.html';
2181                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2182                         SList := TStringList.Create;
2183                         try
2184                                 SList.Clear;
2185                                 FAWKStr.RegExp := '/';
2186                                 if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 5 then begin
2187                                         Result.FBBS := SList[1];
2188                                         Result.FKey := ChangeFileExt(SList[4], '');
2189                                         Result.FFirst := True;
2190                                 end else
2191                                         Exit;
2192                         finally
2193                                 SList.Free;
2194                         end;
2195                         Result.FDone := True;
2196                         Exit;
2197                 end;
2198
2199                 //log\8by\82Ñlog2\8f\91\8e®
2200                 //http://server.2ch.net/log/ITA_NAME/kako/999/999999999.html
2201                 //http://server.2ch.net/log2/ITA_NAME/kako/999/999999999.html
2202                 FAWKStr.RegExp := '/log2?/.+/kako/[0-9]+/[0-9]+\.html';
2203                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2204                         SList := TStringList.Create;
2205                         try
2206                                 SList.Clear;
2207                                 FAWKStr.RegExp := '/';
2208                                 if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 6 then begin
2209                                         Result.FBBS := SList[2];
2210                                         Result.FKey := ChangeFileExt(SList[5], '');
2211                                         Result.FFirst := True;
2212                                 end else
2213                                         Exit;
2214                         finally
2215                                 SList.Free;
2216                         end;
2217                         Result.FDone := True;
2218                         Exit;
2219                 end;
2220
2221
2222                 //\8b\8cURL\8f\91\8e®
2223                 //http://server.2ch.net/test/read.cgi?bbs=ITA_NAME&key=1000000000&st=1&to=5&nofirst=true
2224                 FAWKStr.RegExp := '/test/read\.cgi\?';
2225                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2226                         s := Copy(s, 16, Length(s));
2227                         SList := TStringList.Create;
2228                         try
2229                                 SList.Clear;
2230                                 FAWKStr.RegExp := '&';
2231                                 if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 2 then begin
2232                                         Result.FFirst := True;
2233                                         for i := 0 to SList.Count - 1 do begin
2234                                                 if Pos('bbs=', SList[i]) = 1 then begin
2235                                                         Result.FBBS := Copy(SList[i], 5, Length(SList[i]));
2236                                                 end else if Pos('key=', SList[i]) = 1 then begin
2237                                                         Result.FKey := Copy(SList[i], 5, Length(SList[i]));
2238                                                 end else if Pos('st=', SList[i]) = 1 then begin
2239                                                         wk := Copy(SList[i], 4, Length(SList[i]));
2240                                                         if IsNumeric(wk) then
2241                                                                 Result.FSt := StrToInt(wk)
2242                                                         else if wk = '' then
2243                                                                 Result.FStBegin := True;
2244                                                 end else if Pos('to=', SList[i]) = 1 then begin
2245                                                         wk := Copy(SList[i], 4, Length(SList[i]));
2246                                                         if IsNumeric(wk) then
2247                                                                 Result.FTo := StrToInt(wk)
2248                                                         else if wk = '' then
2249                                                                 Result.FToEnd := True;
2250                                                 end else if Pos('nofirst=', SList[i]) = 1 then begin
2251                                                         Result.FFirst := False;
2252                                                 end;
2253                                         end;
2254                                 end else
2255                                         Exit;
2256                         finally
2257                                 SList.Free;
2258                         end;
2259
2260                         if (Result.FBBS <> '') and (Result.FKey <> '') then begin
2261                                 Result.FDone := True;
2262                         end;
2263                         Exit;
2264                 end;
2265         end;
2266 end;
2267
2268 {!
2269 \brief URI \82ð\95ª\89ð
2270 \param URL      \95ª\89ð\82·\82é URI
2271 \param Protocol OUT:\83v\83\8d\83g\83R\83\8b\82ª\95Ô\82é(ex. http)
2272 \param Host     OUT:\83z\83X\83g\82ª\95Ô\82é(ex. hoge.com)
2273 \param Path     OUT:\92\86\8aÔ\83p\83X\82ª\95Ô\82é(ex. test/read.cgi)
2274 \param Document OUT:\83h\83L\83\85\83\81\83\93\83g\96¼\82ª\95Ô\82é(ex. index.html)
2275 \param Port     OUT:\83|\81[\83g\82ª\95Ô\82é(ex. 8080)
2276 \param Bookmark OUT:\83u\83b\83N\83}\81[\83N(?)\82ª\95Ô\82é
2277 }
2278 procedure TGikoSys.ParseURI(const URL : string; var Protocol, Host, Path, Document, Port, Bookmark: string);
2279 var
2280         URI: TIdURI;
2281 begin
2282         Protocol := '';
2283         Host := '';
2284         Path := '';
2285         Document := '';
2286         Port := '';
2287         Bookmark := '';
2288         URI := TIdURI.Create(URL);
2289         try
2290                 Protocol := URI.Protocol;
2291                 Host := URI.Host;
2292                 Path := URI.Path;
2293                 Document := URI.Document;
2294                 Port := URI.Port;
2295                 Bookmark := URI.Bookmark;
2296         finally
2297                 URI.Free;
2298         end;
2299 end;
2300
2301 {!
2302 \brief \83M\83R\83i\83r\82Ì\83o\81[\83W\83\87\83\93\82ð\8eæ\93¾
2303 \return \83o\81[\83W\83\87\83\93\82Ì\89º 2 \8c\85(dwFileVersionLS)
2304 }
2305 function TGikoSys.GetVersionBuild: Integer;
2306 var
2307         FixedFileInfo: PVSFixedFileInfo;
2308         VersionHandle, VersionSize: DWORD;
2309         pVersionInfo: Pointer;
2310         ItemLen : UInt;
2311         AppFile: string;
2312 begin
2313         Result := 0;
2314         AppFile := Application.ExeName;
2315         VersionSize := GetFileVersionInfoSize(pChar(AppFile), VersionHandle);
2316         if VersionSize = 0 then
2317                 Exit;
2318         GetMem(pVersionInfo, VersionSize);
2319         try
2320                 if GetFileVersionInfo(PChar(AppFile),VersionHandle,VersionSize, pVersionInfo) then
2321                         if VerQueryValue(pVersionInfo, '\', Pointer(FixedFileInfo), ItemLen) then
2322                                 Result := LOWORD(FixedFileInfo^.dwFileVersionLS);
2323         finally
2324                 FreeMem(pVersionInfo, VersionSize);
2325         end;
2326 end;
2327
2328 {!
2329 \brief \83X\83\8c\83b\83h URL \82Ì\90³\8bK\89»
2330 \param inURL \90³\8bK\89»\82·\82é\83X\83\8c\83b\83h URL
2331 \return      \90³\8bK\89»\82³\82ê\82½\83X\83\8c\83b\83h URL
2332
2333 \83X\83\8c\83b\83h URL \82ð\83M\83R\83i\83r\82Ì\92\86\82Å\88ê\88Ó\82È\82à\82Ì\82É\90³\8bK\89»\82µ\82Ü\82·\81B
2334 \88ê\88Ó\82È URL \82É\82·\82é\8e\96\82Å\81AURL \82©\82ç\83X\83\8c\83b\83h\82ð\93±\82«\8fo\82·\8dì\8bÆ\82ð\8dÅ\93K\89»\82µ\82Ü\82·\81B\n
2335 \90³\8bK\89»\82Ì\95û\90j\82Æ\82µ\82Ä\81A\83T\83C\83g\82ª\90\84\8f§\82·\82é\83f\83t\83H\83\8b\83g\82Ì URL \82É\82È\82é\82æ\82¤\82É\90S\82ª\82¯\82Ü\82·\81B
2336 (1-1000 \82Ì\82æ\82¤\82È\95\89\89×\82ð\82©\82¯\82é\82à\82Ì\82É\82Í\82µ\82È\82¢\82±\82Æ)
2337
2338 \97á(\90³\8bK\89»\91O):\n
2339 http://\92\86\97ª/ \n
2340 http://\92\86\97ª/20-100
2341
2342 (\90³\8bK\89»\8cã):\n
2343 http://\92\86\97ª/l50
2344 }
2345 function        TGikoSys.GetBrowsableThreadURL(
2346         inURL : string
2347 ) : string;
2348 var
2349         threadItem      : TThreadItem;
2350         boardPlugIn     : TBoardPlugIn;
2351     board               : TBoard;
2352         i                                               : Integer;
2353 begin
2354
2355         //===== \83v\83\89\83O\83C\83\93
2356         try
2357                 for i := Length( BoardGroups ) - 1 downto 1 do begin
2358                         if Assigned( Pointer( BoardGroups[i].BoardPlugIn.Module ) ) then begin
2359                                 if BoardGroups[i].BoardPlugIn.AcceptURL( inURL ) = atThread then begin
2360                     board := BBSsFindBoardFromURL( BoardGroups[i].BoardPlugIn.ExtractBoardURL(inURL) );
2361                                         if board <> nil then begin
2362                                                 boardPlugIn := BoardGroups[i].BoardPlugIn;
2363                                                 threadItem      := TThreadItem.Create( boardPlugIn, board, inURL );
2364                                                 Result                  := threadItem.URL;
2365                                                 threadItem.Free;
2366
2367                                         end;
2368                                         Exit;
2369                                 end;
2370                         end;
2371                 end;
2372         except
2373                 // exception \82ª\94­\90\82µ\82½\8fê\8d\87\82Í\93à\95\94\8f\88\97\9d\82É\94C\82¹\82½\82¢\82Ì\82Å\82±\82±\82Å\82Í\89½\82à\82µ\82È\82¢
2374         end;
2375
2376         if Length( Result ) = 0 then
2377                 Result := GikoSys.Get2chBrowsableThreadURL( inURL );
2378
2379 end;
2380
2381 {!
2382 \brief \83X\83\8c\83b\83h URL \82ð\94 URL \82É\95Ï\8a·
2383 \param inURL \83X\83\8c\83b\83h URL
2384 \return      \94 URL
2385 }
2386 function        TGikoSys.GetThreadURL2BoardURL(
2387         inURL : string
2388 ) : string;
2389 var
2390         threadItem      : TThreadItem;
2391         boardPlugIn     : TBoardPlugIn;
2392     board               : TBoard;
2393         i                                               : Integer;
2394 begin
2395
2396         //===== \83v\83\89\83O\83C\83\93
2397         try
2398                 for i := Length( BoardGroups ) - 1 downto 1 do begin
2399                         if Assigned( Pointer( BoardGroups[i].BoardPlugIn.Module ) ) then begin
2400                                 if BoardGroups[i].BoardPlugIn.AcceptURL( inURL ) = atThread then begin
2401                     board               := BBSsFindBoardFromURL(BoardGroups[i].BoardPlugIn.ExtractBoardURL(inURL));
2402                                         boardPlugIn := BoardGroups[i].BoardPlugIn;
2403                                         threadItem      := TThreadItem.Create( boardPlugIn, board, inURL );
2404                                         Result                  := BoardGroups[i].BoardPlugIn.GetBoardURL( Longword( threadItem ) );
2405                                         threadItem.Free;
2406
2407                                         Break;
2408                                 end;
2409                         end;
2410                 end;
2411         except
2412                 // exception \82ª\94­\90\82µ\82½\8fê\8d\87\82Í\93à\95\94\8f\88\97\9d\82É\94C\82¹\82½\82¢\82Ì\82Å\82±\82±\82Å\82Í\89½\82à\82µ\82È\82¢
2413         end;
2414
2415         if Length( Result ) = 0 then
2416                 Result := GikoSys.Get2chThreadURL2BoardURL( inURL );
2417
2418 end;
2419
2420 {!
2421 \brief 2ch\97p:\83X\83\8c\83b\83h URL \82ð\94 URL \82É\95Ï\8a·
2422 \param inURL \83X\83\8c\83b\83h URL
2423 \return      \94 URL
2424 \see TGikoSys.GetThreadURL2BoardURL
2425 }
2426 function        TGikoSys.Get2chThreadURL2BoardURL(
2427         inURL : string
2428 ) : string;
2429 var
2430         Protocol, Host, Path, Document, Port, Bookmark : string;
2431         BBSID, BBSKey : string;
2432         foundPos                        : Integer;
2433 begin
2434
2435         ParseURI( inURL, Protocol, Host, Path, Document, Port, Bookmark );
2436         Parse2chURL( inURL, Path, Document, BBSID, BBSKey );
2437
2438         foundPos := Pos( '/test/read.cgi', inURL );
2439         if {(Is2chHost(Host)) and} (foundPos > 0) then
2440                 Result := Copy( inURL, 1, foundPos ) + BBSID + '/'
2441         else
2442                 Result := Protocol + '://' + Host + '/' + BBSID + '/';
2443
2444 end;
2445
2446 {!
2447 \brief 2ch\97p:\83X\83\8c\83b\83h URL \82Ì\90³\8bK\89»
2448 \param inURL \90³\8bK\89»\82·\82é\83X\83\8c\83b\83h URL
2449 \return      \90³\8bK\89»\82³\82ê\82½\83X\83\8c\83b\83h URL
2450 \see TGikoSys.GetBrowsableThreadURL
2451 }
2452 function        TGikoSys.Get2chBrowsableThreadURL(
2453         inURL                   : string
2454 ) : string;
2455 var
2456         Protocol, Host, Path, Document, Port, Bookmark : string;
2457         BBSID, BBSKey : string;
2458         foundPos        : Integer;
2459 begin
2460
2461 //      if Pos( KAKO_PATH, inURL ) > 0 then begin
2462 //              Result := inURL;
2463 //      end else begin
2464                 ParseURI( inURL, Protocol, Host, Path, Document, Port, Bookmark );
2465                 Parse2chURL( inURL, Path, Document, BBSID, BBSKey );
2466                 foundPos := Pos( '/test/read.cgi', inURL ) - 1;
2467
2468                 if Is2chHost( Host ) then begin
2469                         Result := Protocol + '://' + Host +
2470                                 READ_PATH + BBSID + '/' + BBSKey + '/l50';
2471                 end else begin
2472                         if foundPos > 0 then
2473                                 Result := Copy( inURL, 1, foundPos ) +
2474                                         OLD_READ_PATH + 'bbs=' + BBSID + '&key=' + BBSKey + '&ls=50'
2475                         else
2476                                 Result := Protocol + '://' + Host +
2477                                         OLD_READ_PATH + 'bbs=' + BBSID + '&key=' + BBSKey + '&ls=50';
2478                 end;
2479 //      end;
2480
2481 end;
2482
2483 {!
2484 \brief 2ch\97p:\94 URL \82©\82ç\83X\83\8c\83b\83h URL \82ð\8dì\90¬
2485 \param inBoard \94 URL
2486 \param inKey   \83X\83\8c\83b\83h\83L\81[(ex. 1000000000)
2487 \return        \83X\83\8c\83b\83h URL
2488 }
2489 function        TGikoSys.Get2chBoard2ThreadURL(
2490         inBoard : TBoard;
2491         inKey           : string
2492 ) : string;
2493 var
2494         server  : string;
2495 begin
2496
2497         server := UrlToServer( inBoard.URL );
2498         //if Is2chHost( server ) then
2499         if inBoard.Is2ch then
2500                 Result := server + 'test/read.cgi/' + inBoard.BBSID + '/' + inKey + '/l50'
2501         else
2502                 Result := server + 'test/read.cgi?bbs=' + inBoard.BBSID + '&key=' + inKey + '&ls=50';
2503
2504 end;
2505
2506 {!
2507 \brief \83{\81[\83h\83t\83@\83C\83\8b\97ñ\8b\93
2508
2509 \97ñ\8b\93\82³\82ê\82½ BBS(\83{\81[\83h) \82Í BBSs \82É\93ü\82è\82Ü\82·\81B
2510 }
2511 procedure TGikoSys.ListBoardFile;
2512 var
2513         boardFileList   : TStringList;
2514         i, l                    : Integer;
2515 begin
2516         // BBS \82Ì\8aJ\95ú
2517         try
2518           for i := 0 to Length( BBSs ) - 1 do
2519                 BBSs[ i ].Free;
2520         except
2521         end;
2522         SetLength( BBSs, 0 );
2523
2524         l := 0;
2525         // \94Â\83\8a\83X\83g\82Ì\97ñ\8b\93
2526         if FileExists( GikoSys.GetBoardFileName ) then begin
2527           SetLength( BBSs, l + 1 );
2528           BBSs[ l ]                             := TBBS.Create( GikoSys.GetBoardFileName );
2529           BBSs[ l ].Title       := '\82Q\82¿\82á\82ñ\82Ë\82é';
2530                   Inc( l );
2531         end;
2532
2533         if FileExists( GikoSys.GetCustomBoardFileName ) then begin
2534           SetLength( BBSs, l + 1 );
2535           BBSs[ l ]                             := TBBS.Create( GikoSys.GetCustomBoardFileName );
2536           BBSs[ l ].Title       := '\82»\82Ì\91¼';
2537                   Inc( l );
2538         end;
2539
2540         // Board \83t\83H\83\8b\83_
2541         if DirectoryExists( GikoSys.Setting.GetBoardDir ) then begin
2542           BoardFileList := TStringList.Create;
2543           try
2544         BoardFileList.BeginUpdate;
2545                 GikoSys.GetFileList( GikoSys.Setting.GetBoardDir, '*.txt', BoardFileList, True, True );
2546         BoardFileList.EndUpdate;
2547         SetLength( BBSs, l + BoardFileList.Count );
2548                 for i := BoardFileList.Count - 1 downto 0 do begin
2549                   BBSs[ l ]                             := TBBS.Create( BoardFileList[ i ] );
2550                   BBSs[ l ].Title       := ChangeFileExt( ExtractFileName( BoardFileList[ i ] ), '' );
2551                   Inc( l );
2552                 end;
2553           finally
2554                 BoardFileList.Free;
2555           end;
2556         end;
2557 end;
2558
2559 {!
2560 \brief \83{\81[\83h\83t\83@\83C\83\8b\93Ç\82Ý\8d\9e\82Ý
2561 \param bbs \83{\81[\83h\83t\83@\83C\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ BBS
2562 }
2563 procedure TGikoSys.ReadBoardFile( bbs : TBBS );
2564 var
2565 //      idx                                             : Integer;
2566         ini                                             : TMemIniFile;
2567         p : Integer;
2568         boardFile                       : TStringList;
2569         CategoryList    : TStringList;
2570         BoardList                       : TStringList;
2571         Category                        : TCategory;
2572         Board                                   : TBoard;
2573         inistr                          : string;
2574         tmpstring                       : string;
2575 //      RoundItem                       : TRoundItem;
2576
2577         i, iBound                       : Integer;
2578         j, jBound                       : Integer;
2579         k, kBound                       : Integer;
2580 begin
2581
2582         if not FileExists( bbs.FilePath ) then
2583                 Exit;
2584
2585         bbs.Clear;
2586         ini := TMemIniFile.Create('');
2587         boardFile := TStringList.Create;
2588
2589         try
2590                 boardFile.LoadFromFile( bbs.FilePath );
2591
2592                 ini.SetStrings( boardFile );
2593                 CategoryList    := TStringList.Create;
2594                 BoardList                       := TStringList.Create;
2595                 try
2596                         ini.ReadSections( CategoryList );
2597
2598                         iBound := CategoryList.Count - 1;
2599                         for i := 0 to iBound do begin
2600                                 ini.ReadSection( CategoryList[i], BoardList );
2601                                 Category                                := TCategory.Create;
2602                                 Category.No                     := i + 1;
2603                                 Category.Title  := CategoryList[i];
2604
2605                                 jBound := BoardList.Count - 1;
2606                                 for j := 0 to jBound do begin
2607                                         Board := nil;
2608                                         inistr := ini.ReadString(CategoryList[i], BoardList[j], '');
2609                                         //'http://'\82ð\8aÜ\82Ü\82È\82¢\95\8e\9a\97ñ\82Ì\8e\9e\82Í\96³\8e\8b\82·\82é
2610                                         if (AnsiPos('http://', AnsiLowerCase(inistr)) = 0) then Continue;
2611                                         //===== \83v\83\89\83O\83C\83\93
2612                                         try
2613                                                 kBound := Length(BoardGroups) - 1;
2614                                                 for k := 1 to kBound do begin  //0\82Í\81A2\82¿\82á\82ñ
2615                                                         if Assigned( Pointer( BoardGroups[k].BoardPlugIn.Module ) ) then begin
2616                                                                 if BoardGroups[k].BoardPlugIn.AcceptURL( inistr ) = atBoard then begin
2617                                                                         if not BoardGroups[k].Find(inistr, p) then begin
2618                                                                                 tmpstring := BoardGroups[k].BoardPlugIn.ExtractBoardURL( inistr );
2619                                                                                 if AnsiCompareStr(tmpString, inistr) <> 0 then begin
2620                                                                                         if not BoardGroups[k].Find(tmpstring, p) then begin
2621                                                                                                 try
2622                                                                                                         Board := TBoard.Create( BoardGroups[k].BoardPlugIn, tmpstring );
2623                                                                                                         BoardGroups[k].AddObject(tmpstring, Board);
2624                                                                                                         Category.Add(Board);
2625                                                                                                 except
2626                                                                                                         //\82±\82±\82É\97\88\82é\82Æ\82µ\82½\82çBoard\82Ì\8dì\90¬\82É\8e¸\94s\82µ\82½\82Æ\82«\82¾\82©\82çBoard\82ðnil\82É\82·\82é
2627                                                                                                         Board := nil;
2628                                                                                                 end;
2629                                                                                         end else begin
2630                                                                                                 Board := TBoard(BoardGroups[k].Objects[p]);
2631                                                                                                 if Board.ParentCategory <> Category then
2632                                                                                                         Category.Add(Board);
2633                                                                                         end;
2634                                                                                 end else begin
2635                                                                                         try
2636                                                                                                 Board := TBoard.Create( BoardGroups[k].BoardPlugIn, tmpstring );
2637                                                                                                 BoardGroups[k].AddObject(tmpstring, Board);
2638                                                                                                 Category.Add(Board);
2639                                                                                         except
2640                                                                                                 //\82±\82±\82É\97\88\82é\82Æ\82µ\82½\82çBoard\82Ì\8dì\90¬\82É\8e¸\94s\82µ\82½\82Æ\82«\82¾\82©\82çBoard\82ðnil\82É\82·\82é
2641                                                                                                 Board := nil;
2642                                                                                         end;
2643                                                                                 end;
2644                                                                         end else begin
2645                                                                                 Board := TBoard(BoardGroups[k].Objects[p]);
2646                                                                                 if Board.ParentCategory <> Category then
2647                                                                                         Category.Add(Board);
2648                                                                         end;
2649                                                                         Break;
2650                                                                 end;
2651                                                         end;
2652                                                 end;
2653                                         except
2654                                                 // exception \82ª\94­\90\82µ\82½\8fê\8d\87\82Í\93à\95\94\8f\88\97\9d\82É\94C\82¹\82½\82¢\82Ì\82Å\82±\82±\82Å\82Í\89½\82à\82µ\82È\82¢
2655                                         end;
2656                                         try
2657                                                 if (Board = nil) then begin
2658                                                         if not BoardGroups[0].Find(inistr,p) then begin
2659                                                                 Board := TBoard.Create( nil, inistr );
2660                                                                 BoardGroups[0].AddObject(inistr, Board);
2661                                                                 Category.Add(Board);
2662                                                         end else begin
2663                                                                 Board := TBoard(BoardGroups[0].Objects[p]);
2664                                                                 if Board.ParentCategory <> Category then
2665                                                                         Category.Add(Board);
2666                                                         end;
2667                                                 end;
2668
2669                                                 if (Board.Multiplicity = 0) then begin
2670                                                         Board.BeginUpdate;
2671                                                         Board.No := j + 1;
2672                             Board.Multiplicity := 1;
2673                                                         Board.Title := BoardList[j];
2674                                                         Board.RoundDate := ZERO_DATE;
2675                                                         Board.LoadSettings;
2676                                                         Board.EndUpdate;
2677                                                 end else begin
2678                                                         Board.No := j + 1;
2679                                                         Board.Multiplicity := Board.Multiplicity + 1;
2680                                                 end;
2681                                         except
2682                                         end;
2683                                 end;
2684                                 bbs.Add( Category );
2685                         end;
2686
2687
2688                   //end;
2689                   bbs.IsBoardFileRead := True;
2690           finally
2691                 BoardList.Free;
2692                 CategoryList.Free;
2693           end;
2694   finally
2695         boardFile.Free;
2696         ini.Free;
2697   end;
2698
2699 end;
2700
2701 {!
2702 \brief \96¼\8fÌ\82ª\95s\96¾\82È\83J\83e\83S\83\8a\82Ì\90\90¬
2703 \return \90\90¬\82³\82ê\82½\83J\83e\83S\83\8a
2704 }
2705 function        TGikoSys.GetUnknownCategory : TCategory;
2706 const
2707         UNKNOWN_CATEGORY = '(\96¼\8fÌ\95s\96¾)';
2708 begin
2709
2710         if Length( BBSs ) < 2 then begin
2711                 Result := nil;
2712                 Exit;
2713         end;
2714
2715         Result := BBSs[ 1 ].FindCategoryFromTitle( UNKNOWN_CATEGORY );
2716         if Result = nil then begin
2717                 Result                          := TCategory.Create;
2718                 Result.Title    := UNKNOWN_CATEGORY;
2719                 BBSs[ 1 ].Add( Result );
2720         end;
2721
2722 end;
2723
2724 {!
2725 \brief \96¼\8fÌ\82ª\95s\96¾\82È BBS \82Ì\90\90¬
2726 \return \90\90¬\82³\82ê\82½ BBS
2727 }
2728 function        TGikoSys.GetUnknownBoard( inPlugIn : TBoardPlugIn; inURL : string ) : TBoard;
2729 var
2730         category : TCategory;
2731 const
2732         UNKNOWN_BOARD = '(\96¼\8fÌ\95s\96¾)';
2733 begin
2734
2735         category := GetUnknownCategory;
2736         if category = nil then begin
2737                 Result := nil;
2738         end else begin
2739                 Result := category.FindBoardFromTitle( UNKNOWN_BOARD );
2740                 if Result = nil then begin
2741                         Result                          := TBoard.Create( inPlugIn, inURL );
2742                         Result.Title    := UNKNOWN_BOARD;
2743                         category.Add( Result );
2744                 end;
2745         end;
2746
2747 end;
2748
2749 //! Samba.ini
2750 function TGikoSys.GetSambaFileName : string;
2751 begin
2752         Result := Setting.GetSambaFileName;
2753 end;
2754
2755 {!
2756 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\83A\83\93\83J\81[\82É\82µ\82Ä\97ñ\8b\93
2757 \param AID        \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
2758 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
2759 \param limited    \97ñ\8b\93\82·\82é\90\94\82ð\90§\8cÀ\82·\82é\82È\82ç1\88È\8fã
2760 \return           \97ñ\8b\93\82³\82ê\82½\83\8c\83X\83A\83\93\83J\81[
2761 }
2762 function TGikoSys.GetSameIDResAnchor(
2763     const AID : string; ThreadItem: TThreadItem;
2764     limited: Integer):string;
2765 var
2766         i: integer;
2767         body: TStringList;
2768     Res: TResRec;
2769     ResLink : TResLinkRec;
2770 begin
2771     // body\88È\8aO\82Í\8eg\97p\82µ\82È\82¢\82Ì\82Å\8f\89\8aú\89»\82µ\82È\82¢
2772     Res.FBody := '';
2773     Res.FType := glt2chNew;
2774
2775                 Result := '';
2776                 if (not IsNoValidID(AID)) and
2777                         (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
2778                                 body := TStringList.Create;
2779                                 try
2780                                                 GetSameIDRes(AID, ThreadItem, body);
2781                                                 if (limited > 0) and (body.Count > limited) then begin
2782                                                                 for i := body.Count - limited to body.Count - 1 do begin
2783                                                                                 Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
2784                                                                 end;
2785                                                 end else begin
2786                                                                 for i := 0 to body.Count - 1 do begin
2787                                                                                 Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
2788                                                                 end;
2789                                                 end;
2790                                 finally
2791                                                 body.Free;
2792                                 end;
2793         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
2794         ResLink.FKey := ChangeFileExt(ThreadItem.FileName, '');
2795         HTMLCreater.ConvRes(@Res, @ResLink, false);
2796         Result := Res.FBody;
2797                 end;
2798 end;
2799
2800 {!
2801 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\97ñ\8b\93
2802 \param AID        \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
2803 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
2804 \param body       OUT:\97ñ\8b\93\82³\82ê\82½\83\8c\83X\94Ô\8d\86\82ª\95Ô\82é
2805 }
2806 procedure TGikoSys.GetSameIDRes(const AID : string; ThreadItem: TThreadItem;var body: TStringList);
2807 var
2808         i: integer;
2809         ReadList: TStringList;
2810         Res: TResRec;
2811         boardPlugIn : TBoardPlugIn;
2812 begin
2813         if (not IsNoValidID(AID)) and
2814         (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
2815                 //if ThreadItem.IsBoardPlugInAvailable then begin
2816         if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
2817                         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
2818                         //boardPlugIn           := ThreadItem.BoardPlugIn;
2819             boardPlugIn         := ThreadItem.ParentBoard.BoardPlugIn;
2820
2821                         for i := 0 to threadItem.Count - 1 do begin
2822                                 // \83\8c\83X
2823                                 THTMLCreate.DivideStrLine(boardPlugIn.GetDat(DWORD( threadItem ), i + 1), @Res);
2824                                 if(AnsiPos(AID, Res.FDateTime) > 0) then begin
2825                                         body.Add(IntToStr(i+1));
2826                                 end;
2827                         end;
2828                 end else begin
2829                         ReadList := TStringList.Create;
2830                         try
2831                                 ReadList.LoadFromFile(ThreadItem.GetThreadFileName);
2832                                 for i := 0 to ReadList.Count - 1 do begin
2833                                         THTMLCreate.DivideStrLine(ReadList[i], @Res);
2834                                         if AnsiPos(AID, Res.FDateTime) > 0 then begin
2835                                                 body.Add(IntToStr(i+1));
2836                                         end;
2837                                 end;
2838                         finally
2839                                 ReadList.Free;
2840                         end;
2841                 end;
2842         end;
2843 end;
2844
2845 {!
2846 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\97ñ\8b\93
2847 \param AIDNum     \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
2848 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
2849 \param limited    \97ñ\8b\93\82·\82é\90\94\82ð\90§\8cÀ\82·\82é\82È\82ç1\88È\8fã
2850 \return
2851 }
2852 function TGikoSys.GetSameIDResAnchor(AIDNum : Integer;
2853      ThreadItem: TThreadItem;
2854      limited: Integer):string;
2855 var
2856         i: integer;
2857         body: TStringList;
2858     Res: TResRec;
2859     ResLink : TResLinkRec;
2860 begin
2861     // body\88È\8aO\82Í\8eg\97p\82µ\82È\82¢\82Ì\82Å\8f\89\8aú\89»\82µ\82È\82¢
2862     Res.FBody := '';
2863     Res.FType := glt2chNew;
2864
2865         Result := '';
2866         if (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
2867                 body := TStringList.Create;
2868                 try
2869                         GetSameIDRes(AIDNum, ThreadItem, body);
2870             if (limited > 0) and ( body.Count > limited) then begin
2871                 for i := body.Count - 20 to body.Count - 1 do begin
2872                     Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
2873                 end;
2874             end else begin
2875                         for i := 0 to body.Count - 1 do begin
2876                                 Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
2877                         end;
2878             end;
2879                 finally
2880                         body.Free;
2881                 end;
2882         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
2883         ResLink.FKey := ChangeFileExt(ThreadItem.FileName, '');
2884         HTMLCreater.ConvRes(@Res, @ResLink, false);
2885         Result := Res.FBody;
2886         end;
2887 end;
2888
2889 {!
2890 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\97ñ\8b\93
2891 \param AIDNum     \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
2892 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
2893 \param body       OUT:\97ñ\8b\93\82³\82ê\82½\83\8c\83X\94Ô\8d\86\82ª\95Ô\82é
2894 }
2895 procedure TGikoSys.GetSameIDRes(AIDNum : Integer; ThreadItem: TThreadItem;var body: TStringList);
2896 var
2897         AID : String;
2898 begin
2899     AID := GetResID(AIDNum, ThreadItem);
2900     if not IsNoValidID(AID) then begin
2901             GetSameIDRes(AID, ThreadItem, body);
2902         end;
2903 end;
2904 {!
2905 \brief \93\8a\8de ID \8eæ\93¾
2906 \param AIDNum     \93\8a\8d\83\8c\83X\94Ô\8d\86
2907 \param ThreadItem \93\8a\8de\83X\83\8c\83b\83h
2908 \param body       OUT:\93\8a\8deID
2909 }
2910 function TGikoSys.GetResID(AIDNum: Integer; ThreadItem: TThreadItem): String;
2911 var
2912         Res: TResRec;
2913         boardPlugIn : TBoardPlugIn;
2914         stList: TStringList;
2915         i : Integer;
2916 begin
2917     Result := '';
2918         if (ThreadItem <> nil) and (ThreadItem.IsLogFile)
2919                 and (AIDNum > 0) and (AIDNum <= ThreadItem.Count) then begin
2920                 //if ThreadItem.IsBoardPlugInAvailable then begin
2921         if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
2922                         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
2923                         //boardPlugIn           := ThreadItem.BoardPlugIn;
2924             boardPlugIn         := ThreadItem.ParentBoard.BoardPlugIn;
2925                         THTMLCreate.DivideStrLine(boardPlugIn.GetDat(DWORD( threadItem ), AIDNum), @Res);
2926                 end else begin
2927                         THTMLCreate.DivideStrLine( ReadThreadFile(ThreadItem.GetThreadFileName, AIDNum), @Res);
2928                 end;
2929                 Result := Res.FDateTime;
2930                 if AnsiPos('id', AnsiLowerCase(Result)) > 0 then begin
2931                         Result := Copy(Result, AnsiPos('id', AnsiLowerCase(Result)) - 1, 11);
2932             if AnsiPos(' be:', AnsiLowerCase(Result)) > 0 then begin
2933                 Result := Copy(Result, 1, AnsiPos(' BE:', AnsiLowerCase(Result)) - 1)
2934             end;
2935                 end else begin
2936                         stlist := TStringList.Create;
2937                         try
2938                                 stList.DelimitedText := Result;
2939                 Result := '';
2940                                 for i := 0 to stList.Count - 1 do
2941                                         if Length(WideString(stList[i])) = 8 then begin
2942                                                 if NotDateorTimeString(stList[i]) then begin
2943                                                         Result := stList[i];
2944                                                         break;
2945                                                 end;
2946                                         end;
2947                         finally
2948                                 stList.Free;
2949                         end;
2950                 end;
2951         end;
2952 end;
2953 {!
2954 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\83J\83E\83\93\83g
2955 \param AID        \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
2956 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
2957 \return           \93¯\82¶ ID \82ð\8e\9d\82Â\83\8c\83X\82Ì\90\94
2958 }
2959 function TGikoSys.GetSameIDResCount(const AID : string; ThreadItem: TThreadItem):Integer;
2960 var
2961         body: TStringList;
2962 begin
2963     Result := 0;
2964         if (not IsNoValidID(AID))
2965      and (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
2966                 body := TStringList.Create;
2967                 try
2968                         GetSameIDRes(AID, ThreadItem, body);
2969                         Result := body.Count;
2970                 finally
2971                         body.Free;
2972                 end;
2973         end;
2974
2975 end;
2976
2977 {!
2978 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\83J\83E\83\93\83g
2979 \param AIDNum     \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
2980 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
2981 \return           \93¯\82¶ ID \82ð\8e\9d\82Â\83\8c\83X\82Ì\90\94
2982 }
2983 function TGikoSys.GetSameIDResCount(AIDNum : Integer; ThreadItem: TThreadItem):Integer;
2984 var
2985         body: TStringList;
2986 begin
2987         Result := 0;
2988         if (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
2989                 body := TStringList.Create;
2990                 try
2991                         GetSameIDRes(AIDNum, ThreadItem, body);
2992             Result := body.Count;
2993                 finally
2994                         body.Free;
2995                 end;
2996         end;
2997 end;
2998
2999 {!
3000 \brief \8e\9e\8d\8f\82ð\8e¦\82·\95\8e\9a\97ñ\82Å\82Í\96³\82¢\82©\82Ç\82¤\82©
3001 \param AStr \92²\82×\82é\95\8e\9a\97ñ
3002 \return     \8e\9e\8d\8f\82Å\82Í\96³\82¢\82È\82ç True
3003 \todo \94Û\92è\8c`(Not)\82æ\82è\8dm\92è\8cn(Is)
3004 }
3005 function TGikoSys.NotDateorTimeString(const AStr : string): boolean;
3006 begin
3007         Result := false;
3008         try
3009                 StrToDate(AStr);
3010         except
3011                 try
3012                         StrToTime(AStr);
3013                         Result := false;
3014                 except
3015                         Result := true;
3016                 end;
3017         end;
3018
3019 end;
3020
3021 {!
3022 \brief \83X\83p\83\80:\8cê\90\94\82ð\83J\83E\83\93\83g
3023 \param text      \8c³\82É\82È\82é\95\8fÍ
3024 \param wordCount OUT:\83J\83E\83\93\83g\82³\82ê\82½\92P\8cê\82Ì\88ê\97\97\82ª\95Ô\82é
3025 }
3026 procedure TGikoSys.SpamCountWord( const text : string; wordCount : TWordCount );
3027 begin
3028
3029         if Setting.SpamFilterAlgorithm = gsfaNone then Exit;
3030         Bayesian.CountWord( text, wordCount );
3031
3032 end;
3033
3034 {!
3035 \brief \83X\83p\83\80:\8aw\8fK\8c\8b\89Ê\82ð\95ú\8aü
3036 \param wordCount \95ú\8aü\82·\82é\92P\8cê\82Ì\88ê\97\97
3037 \param isSpam    wordCount \82ª\83X\83p\83\80\82Æ\82µ\82Ä\8aw\8fK\82³\82ê\82Ä\82¢\82½\82È\82ç True
3038 \warning        \8aw\8fK\8dÏ\82Ý\82Ì\95\8fÍ\82©\82Ç\82¤\82©\82Í\8am\94F\8fo\97\88\82Ü\82¹\82ñ\81B\n
3039                                         Learn \82µ\82Ä\82¢\82È\82¢\95\8fÍ\82â isSpam \82ð\8aÔ\88á\82¦\82Ä\8ew\92è\82·\82é\82Æ
3040                                         \83f\81[\83^\83x\81[\83X\82ª\94j\91¹\82µ\82Ü\82·\81B\n
3041                                         \8aw\8fK\8dÏ\82Ý\82©\82Ç\82¤\82©\82Í\93Æ\8e©\82É\8aÇ\97\9d\82µ\82Ä\82­\82¾\82³\82¢\81B
3042
3043 \91S\82Ä\82Ì\8aw\8fK\8c\8b\89Ê\82ð\83N\83\8a\83A\82·\82é\82í\82¯\82Å\82Í\82 \82è\82Ü\82¹\82ñ\81B\n
3044 wordCount \82ð\93¾\82½\95\8fÍ\82Ì\8aw\8fK\8c\8b\89Ê\82Ì\82Ý\83N\83\8a\83A\82µ\82Ü\82·\81B
3045
3046 \8eå\82É\83X\83p\83\80\82Æ\83n\83\80\82ð\90Ø\82è\91Ö\82¦\82é\82½\82ß\82É Forget -> Learn \82Ì\8f\87\82Å\8eg\97p\82µ\82Ü\82·\81B
3047 }
3048 procedure TGikoSys.SpamForget( wordCount : TWordCount; isSpam : Boolean );
3049 begin
3050
3051         if Setting.SpamFilterAlgorithm = gsfaNone then Exit;
3052         Bayesian.Forget( wordCount, isSpam );
3053
3054 end;
3055
3056 {!
3057 \brief \83X\83p\83\80:\8aw\8fK
3058 \param wordCount \8aw\8fK\82·\82é\92P\8cê\82Ì\88ê\97\97
3059 \param isSpam    \83X\83p\83\80\82Æ\82µ\82Ä\8aw\8fK\82·\82é\82È\82ç True
3060 }
3061 procedure TGikoSys.SpamLearn( wordCount : TWordCount; isSpam : Boolean );
3062 begin
3063
3064         if Setting.SpamFilterAlgorithm = gsfaNone then Exit;
3065         Bayesian.Learn( wordCount, isSpam );
3066
3067 end;
3068
3069 {!
3070 \brief \83X\83p\83\80:\95\8fÍ\82ð\89ð\90Í\82µ\81A\83X\83p\83\80\93x\90\94\82ð\93¾\82é
3071 \param text      \8c³\82É\82È\82é\95\8fÍ
3072 \param wordCount OUT:\83J\83E\83\93\83g\82³\82ê\82½\92P\8cê\82Ì\88ê\97\97\82ª\95Ô\82é(SpamCountWord \82Æ\93¯\93\99)
3073 \return          0\81`1 \82Ì\83X\83p\83\80\93x\90\94
3074 }
3075 function TGikoSys.SpamParse( const text : string; wordCount : TWordCount ) : Extended;
3076 begin
3077
3078         case Setting.SpamFilterAlgorithm of
3079         gsfaNone:                                                               Result := 0;
3080         gsfaPaulGraham:                                 Result := Bayesian.Parse( text, wordCount, gbaPaulGraham );
3081         gsfaGaryRobinson:                               Result := Bayesian.Parse( text, wordCount, gbaGaryRobinson );
3082         gsfaGaryRobinsonFisher: Result := Bayesian.Parse( text, wordCount, gbaGaryRobinsonFisher );
3083         else                                                                            Result := 0;
3084         end;
3085
3086 end;
3087
3088 {!
3089 \brief \83\86\81[\83U\90Ý\92è\82Ì CSS \82ð\90\90¬
3090 \return \90\90¬\82³\82ê\82½ CSS
3091
3092 [\83c\81[\83\8b]\83\81\83j\83\85\81[-[\83I\83v\83V\83\87\83\93]-[CSS \82Æ\83X\83L\83\93]\83^\83u\82Ì
3093 [\83t\83H\83\93\83g\82ð\8ew\92è], [\94w\8ci\90F\82ð\8ew\92è] \82É\89\88\82Á\82½ CSS \82ð\90\90¬\82µ\82Ü\82·\81B
3094 }
3095 function TGikoSys.SetUserOptionalStyle(): string;
3096 begin
3097                 Result := '';
3098         if Length( GikoSys.Setting.BrowserFontName ) > 0 then
3099                 Result := 'font-family:"' + GikoSys.Setting.BrowserFontName + '";';
3100         if GikoSys.Setting.BrowserFontSize <> 0 then
3101                 Result := Result + 'font-size:' + IntToStr( GikoSys.Setting.BrowserFontSize ) + 'pt;';
3102         if GikoSys.Setting.BrowserFontColor <> -1 then
3103                 Result := Result + 'color:#' + IntToHex( GikoSys.Setting.BrowserFontColor, 6 ) + ';';
3104         if GikoSys.Setting.BrowserBackColor <> -1 then
3105                 Result := Result + 'background-color:#' + IntToHex( GikoSys.Setting.BrowserBackColor, 6 ) + ';';
3106         case GikoSys.Setting.BrowserFontBold of
3107                 -1: Result := Result + 'font-weight:normal;';
3108                 1:  Result := Result + 'font-weight:bold;';
3109         end;
3110         case GikoSys.Setting.BrowserFontItalic of
3111                 -1: Result := Result + 'font-style:normal;';
3112                 1:  Result := Result + 'font-style:italic;';
3113         end;
3114 end;
3115
3116 {!
3117 \brief Be \83v\83\8d\83t\83@\83C\83\8b\82Ö\82Ì\83A\83\93\83J\81[\83^\83O\82ð\90\90¬
3118 \param AID  \91Î\8fÛ\82Æ\82È\82é\93ú\95tID\95\8e\9a\97ñ
3119 \param ANum \83\8c\83X\94Ô
3120 \param AURL \82»\82Ì\83X\83\8c\83b\83h\82ÌURL
3121 \return     \90\90¬\82³\82ê\82½\83A\83\93\83J\81[\83^\83O
3122 }
3123 function TGikoSys.AddBeProfileLink(AID : string; ANum: Integer):string ;
3124 var
3125         p : integer;
3126         BNum, BMark : string;
3127 begin
3128         p := AnsiPos('BE:', AnsiUpperCase(AID));
3129         if p > 0 then begin
3130                 BNum := Copy(AID, p, Length(AID));
3131                 AID := Copy(AID, 1, p - 1);
3132                 p := AnsiPos('-', BNum);
3133                 if p > 0 then begin
3134                         BMark := '?' + Trim(Copy(BNum, p + 1, Length(BNum)));
3135                         BNum := Copy(BNum, 1, p - 1);
3136                 end;
3137                 BNum := Trim(BNum);
3138                 Result := AID + ' <a href="'  + BNum + '/' + IntToStr(ANum)
3139                         + '" target=_blank>' + BMark + '</a>';
3140         end else
3141                 Result := AID;
3142 end;
3143
3144 {!
3145 \brief \83o\81[\83W\83\87\83\93\8fî\95ñ\82ð\8eæ\93¾
3146 \param KeyWord \8eæ\93¾\82·\82é\8d\80\96Ú
3147 \return        \83o\81[\83W\83\87\83\93\95\8e\9a\97ñ
3148 }
3149 function TGikoSys.GetVersionInfo(KeyWord: TVerResourceKey): string;
3150 const
3151         Translation = '\VarFileInfo\Translation';
3152         FileInfo = '\StringFileInfo\%0.4s%0.4s\';
3153 var
3154         BufSize, HWnd: DWORD;
3155         VerInfoBuf: Pointer;
3156         VerData: Pointer;
3157         VerDataLen: Longword;
3158         PathLocale: String;
3159 begin
3160         // \95K\97v\82È\83o\83b\83t\83@\82Ì\83T\83C\83Y\82ð\8eæ\93¾
3161         BufSize := GetFileVersionInfoSize(PChar(Application.ExeName), HWnd);
3162         if BufSize <> 0 then begin
3163                 // \83\81\83\82\83\8a\82ð\8am\95Û
3164                 GetMem(VerInfoBuf, BufSize);
3165                 try
3166                         GetFileVersionInfo(PChar(Application.ExeName), 0, BufSize, VerInfoBuf);
3167                         // \95Ï\90\94\8fî\95ñ\83u\83\8d\83b\83N\93à\82Ì\95Ï\8a·\83e\81[\83u\83\8b\82ð\8ew\92è
3168                         VerQueryValue(VerInfoBuf, PChar(Translation), VerData, VerDataLen);
3169
3170                         if not (VerDataLen > 0) then
3171                                 raise Exception.Create('\8fî\95ñ\82Ì\8eæ\93¾\82É\8e¸\94s\82µ\82Ü\82µ\82½');
3172
3173                         // 8\8c\85\82Ì\82P\82U\90i\90\94\82É\95Ï\8a·
3174                         // \81¨'\StringFileInfo\027382\FileDescription'
3175                         PathLocale := Format(FileInfo + KeyWordStr[KeyWord],
3176                         [IntToHex(Integer(VerData^) and $FFFF, 4),
3177                         IntToHex((Integer(VerData^) shr 16) and $FFFF, 4)]);
3178                         VerQueryValue(VerInfoBuf, PChar(PathLocale), VerData, VerDataLen);
3179
3180                         if VerDataLen > 0 then begin
3181                                 // VerData\82Í\83[\83\8d\82Å\8fI\82í\82é\95\8e\9a\97ñ\82Å\82Í\82È\82¢\82±\82Æ\82É\92\8d\88Ó
3182                                 result := '';
3183                                 SetLength(result, VerDataLen);
3184                                 StrLCopy(PChar(result), VerData, VerDataLen);
3185                         end;
3186                 finally
3187                         // \89ð\95ú
3188                         FreeMem(VerInfoBuf);
3189                 end;
3190         end;
3191 end;
3192
3193 {!
3194 \brief Load \82³\82ê\82Ä\82¢\82é\83v\83\89\83O\83C\83\93\82Ì\83o\81[\83W\83\87\83\93\82ð\97ñ\8b\93
3195 \return 1\8ds1plugin
3196 }
3197 function TGikoSys.GetPluginsInfo(): String;
3198 var
3199         i : Integer;
3200         major, minor, revision : Cardinal;
3201         agent, release : String;
3202 begin
3203         //\8c\8b\89Ê\82ð\83N\83\8a\83A\82µ\82Ä\82¨\82­
3204         Result := '';
3205
3206         //BoardGroups\8co\97R\82ÅPlugin\82É\83A\83N\83Z\83X\82·\82é
3207         for  i := 0 to Length(BoardGroups) - 1 do begin
3208                 //BoardGroups\82Ì\92\86\82É\82Í\81APlugin\82ð\8e\9d\82Á\82Ä\82¢\82È\82¢\82Ì\81i2\82¿\82á\82ñ\81j\82ª
3209                 //\82¢\82é\82Ì\82Å\82»\82ê\82ð\8f\9c\82­
3210                 if BoardGroups[i].BoardPlugIn <> nil then begin
3211                         BoardGroups[i].BoardPlugIn.VersionInfo(agent, major, minor, release, revision);
3212
3213
3214                         //"Plugin\82Ì\96¼\91O(major.minor.revision)"
3215                         Result := Result +
3216                                 Format('%s(%d.%d.%d)', [agent, major, minor, revision]) + #13#10;
3217                 end;
3218         end;
3219 end;
3220
3221
3222 //! IE\82Ì\83o\81[\83W\83\87\83\93\82ð\8eæ\93¾\82·\82é
3223 function TGikoSys.GetIEVersion: string;
3224 var
3225         R: TRegistry;
3226 begin
3227         R := TRegistry.Create;
3228         try
3229                 //\93Ç\82Ý\8eæ\82è\90ê\97p\82É\82µ\82È\82¢\82Æ\81A\90§\8cÀUSER\82Æ\82©\82Ì\8fê\8d\87\81A\8aJ\82¯\82È\82¢\82Ý\82½\82¢
3230                 R.Access := KEY_EXECUTE;
3231                 R.RootKey := HKEY_LOCAL_MACHINE;
3232                 R.OpenKey('Software\Microsoft\Internet Explorer', False);
3233                 try
3234                         Result := R.ReadString('version');
3235                 except
3236                         Result := '\83o\81[\83W\83\87\83\93\82Ì\8eæ\93¾\82É\8e¸\94s\82µ\82Ü\82µ\82½\81B';
3237                 end;
3238                 R.CloseKey;
3239         finally
3240                 R.Free;
3241         end;
3242 end;
3243 //! main\83t\83H\81[\83\80\82Ì\83V\83\87\81[\83g\83J\83b\83g\83L\81[\82ÌIni\83t\83@\83C\83\8b\96¼
3244 function TGikoSys.GetMainKeyFileName : String;
3245 begin
3246         Result := Setting.GetMainKeyFileName;
3247 end;
3248 //! Editor\83t\83H\81[\83\80\82Ì\83V\83\87\81[\83g\83J\83b\83g\83L\81[\82ÌIni\83t\83@\83C\83\8b\96¼
3249 function TGikoSys.GetEditorKeyFileName: String;
3250 begin
3251         Result := Setting.GetEditorKeyFileName;
3252 end;
3253 //! \93ü\97Í\83A\83V\83X\83g\82Ì\90Ý\92è\83t\83@\83C\83\8b\96¼
3254 function TGikoSys.GetInputAssistFileName: String;
3255 begin
3256         Result := Setting.GetInputAssistFileName;
3257 end;
3258 //! \83M\83R\83i\83r\82Ì\83\81\83b\83Z\81[\83W\82ð\90Ý\92è\82·\82é
3259 procedure TGikoSys.SetGikoMessage;
3260 begin
3261         if FGikoMessage = nil then begin
3262                 FGikoMessage := TGikoMessage.Create;
3263         end else begin
3264                 FGikoMessage.Clear;
3265         end;
3266
3267         if (Setting.GengoSupport) then begin
3268                 try
3269                         if (FileExists(Setting.GetLanguageFileName)) then begin
3270                                 FGikoMessage.LoadFromFile(Setting.GetLanguageFileName);
3271                         end;
3272                 except
3273                         FGikoMessage.Clear;
3274                 end;
3275         end;
3276 end;
3277 //! \83M\83R\83i\83r\82Ì\83\81\83b\83Z\81[\83W\82ð\8eæ\93¾\82·\82é
3278 function TGikoSys.GetGikoMessage(MesType: TGikoMessageListType): String;
3279 begin
3280     Result := '';
3281         if FGikoMessage <> nil then begin
3282                 Result := FGikoMessage.GetMessage(MesType);
3283         end;
3284 end;
3285
3286 //Tue, 17 Dec 2002 12:18:07 GMT \81¨ TDateTime\82Ö
3287 //MonaUtils\82©\82ç\88Ú\93®
3288 function  TGikoSys.DateStrToDateTime(const DateStr: string): TDateTime;
3289         function  StrMonthToMonth(const s: string): integer;
3290         const
3291                 m: array[1..12] of string = ('Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec');
3292         var
3293                 i: integer;
3294         begin
3295                 Result  :=  -1;
3296                 for i :=  Low(m)  to  High(m) do  begin
3297                         if  (SameText(s, m[i]))  then  begin
3298                                 Result  :=  i;
3299                                 Break;
3300                         end;
3301                 end;
3302         end;
3303 var
3304         wDay, wMonth, wYear: word;
3305         wHour, wMinute, wSecond: word;
3306         sTime: string;
3307         d: TDateTime;
3308 begin
3309         wDay    :=  StrToIntDef(ChooseString(DateStr, ' ', 1), 0);
3310         wMonth  :=  StrMonthToMonth(ChooseString(DateStr, ' ', 2));
3311         wYear   :=  StrToIntDef(ChooseString(DateStr, ' ', 3), 0);
3312         sTime   :=  ChooseString(DateStr, ' ', 4);
3313         wHour   :=  StrToIntDef(ChooseString(sTime, ':', 0), 0);
3314         wMinute :=  StrToIntDef(ChooseString(sTime, ':', 1), 0);
3315         wSecond :=  StrToIntDef(ChooseString(sTime, ':', 2), 0);
3316         d :=  EncodeDateTime(wYear, wMonth, wDay, wHour, wMinute, wSecond, 0);
3317         Result  :=  d;
3318 end;
3319 //MonaUtils\82©\82ç\88Ú\93®
3320 //! \82 \82é\83Z\83p\83\8c\81[\83^\82Å\8bæ\90Ø\82ç\82ê\82½\95\8e\9a\97ñ\82©\82ç\82\8e\94Ô\96Ú\82Ì\95\8e\9a\97ñ\82ð\8eæ\82è\8fo\82·
3321 function TGikoSys.ChooseString(const Text, Separator: string; Index: integer): string;
3322 var
3323         S : string;
3324         i, p : integer;
3325 begin
3326         S :=  Text;
3327         for i :=  0 to  Index - 1 do  begin
3328                 if  (AnsiPos(Separator, S) = 0) then  S :=  ''
3329                 else  S :=  Copy(S, AnsiPos(Separator, S) + Length(Separator), Length(S));
3330         end;
3331         p :=  AnsiPos(Separator, S);
3332         if  (p > 0) then  Result  :=  Copy(S, 1, p - 1) else Result :=  S;
3333 end;
3334 //! \88ê\8e\9e\83t\83@\83C\83\8b\82©\82ç\82Ì\95\9c\8b\8c
3335 procedure TGikoSys.RestoreThreadData(Board : TBoard);
3336 const
3337     SECTION = 'Setting';
3338 var
3339     TmpFileList : TStringList;
3340     i : Integer;
3341     ini : TMemIniFile;
3342     ThreadItem : TThreadItem;
3343     Boardpath, tmpStr : string;
3344 begin
3345     Boardpath := ExtractFilePath(Board.GetFolderIndexFileName);
3346
3347         TmpFileList := TStringList.Create;
3348         TmpFileList.Sorted := True;
3349         TmpFileList.BeginUpdate;
3350     try
3351         //\91O\89ñ\88Ù\8fí\8fI\97¹\8e\9e\97pTmp\83t\83@\83C\83\8b\83\8a\83X\83g
3352             GetFileList(Boardpath, '*.tmp', TmpFileList, False);
3353             TmpFileList.EndUpdate;
3354                 //\91O\89ñ\88Ù\8fí\8fI\97¹\8e\9e\83`\83F\83b\83N
3355                 for i := TmpFileList.Count - 1 downto 0 do begin
3356                         ThreadItem := Board.FindThreadFromFileName(ChangeFileExt(TmpFileList[i], '.dat'));
3357                         if ThreadItem <> nil then begin
3358                                 ini := TMemIniFile.Create(Boardpath + TmpFileList[i]);
3359                                 try
3360                                         tmpStr := ini.ReadString(SECTION, 'RoundDate', DateTimeToStr(ZERO_DATE));
3361                                         ThreadItem.RoundDate := ConvertDateTimeString(tmpStr);
3362
3363                                         tmpStr := ini.ReadString(SECTION, 'LastModified', DateTimeToStr(ZERO_DATE));
3364                                         ThreadItem.LastModified := ConvertDateTimeString(tmpStr);
3365                                         ThreadItem.Count := ini.ReadInteger(SECTION, 'Count', 0);
3366                                         ThreadItem.NewReceive := ini.ReadInteger(SECTION, 'NewReceive', 0);
3367
3368                                         ThreadItem.Size := ini.ReadInteger(SECTION, 'Size', 0);
3369                     ThreadItem.IsLogFile := FileExists(ThreadItem.GetThreadFileName);
3370                                         if(ThreadItem.Size = 0) and (ThreadItem.IsLogFile) then begin
3371                                                 try
3372                                                         ThreadItem.Size := GetFileSize(ThreadItem.GetThreadFileName) - ThreadItem.Count;
3373                                                 except
3374                                                 end;
3375                                         end;
3376
3377                     //\8f\84\89ñ\82Ì\90Ý\92è\82ÍRoundData\82Ì\95û\82ª\82â\82é\82©\82ç\8f\9f\8eè\82É\90Ý\92è\82µ\82Ä\82Í\83_\83\81\81I\81@by \82à\82\82ã
3378                                         //ThreadItem.Round := ini.ReadBool('Setting', 'Round', False);
3379                                         //ThreadItem.RoundName := ini.ReadString('Setting', 'RoundName', ThreadItem.RoundName);
3380                                         ThreadItem.UnRead := False;//ini.ReadBool('Setting', 'UnRead', False);
3381                                         ThreadItem.ScrollTop := ini.ReadInteger(SECTION, 'ScrollTop', 0);
3382                                         ThreadItem.AllResCount := ini.ReadInteger(SECTION, 'AllResCount', ThreadItem.Count);
3383                                         ThreadItem.NewResCount := ini.ReadInteger(SECTION, 'NewResCount', 0);
3384                                         ThreadItem.AgeSage := TGikoAgeSage(ini.ReadInteger(SECTION, 'AgeSage', Ord(gasNone)));
3385                                 finally
3386                                         ini.Free;
3387                                 end;
3388                                 DeleteFile(Boardpath + TmpFileList[i]);
3389                         end;
3390                 end;
3391     finally
3392         TmpFileList.Clear;
3393         TmpFileList.Free;
3394     end;
3395 end;
3396 {
3397 \brief User32.dll\82ª\97\98\97p\82Å\82«\82é\82©
3398 \return Boolean \97\98\97p\82Å\82«\82é\8fê\8d\87\82ÍTrue
3399 }
3400 function TGikoSys.CanUser32DLL: Boolean;
3401 var
3402     hUser32 : HINST;
3403 begin
3404     Result := False;
3405         hUser32 := 0;
3406         try
3407                 try
3408                         hUser32 := LoadLibrary('User32.dll');
3409                         if hUser32 <> 0 then begin
3410                                 Result := True;
3411             end;
3412                 except
3413                 Result := false;
3414                 end;
3415         finally
3416                 FreeLibrary(hUser32);
3417         end;
3418 end;
3419 {
3420 \brief  OE\88ø\97p\95\84\8eæ\93¾
3421 \return OE\82Ì\88ø\97p\95\84\81i\90Ý\92è\82³\82ê\82Ä\82¢\82È\82¢\8fê\8d\87\82Í'>')
3422 }
3423 function TGikoSys.GetOEIndentChar : string;
3424 var
3425         regKey                  : TRegistry;
3426         Identities      : string;
3427         IndentChar      : DWORD;
3428 const
3429         DEFAULT_CHAR    = '> ';
3430         OE_MAIL_PATH    = '\Software\Microsoft\Outlook Express\5.0\Mail';
3431         INDENT_CHAR             = 'Indent Char';
3432 begin
3433
3434         Result  := DEFAULT_CHAR;
3435         regKey  := TRegistry.Create;
3436         try
3437                 try
3438                         regKey.RootKey  := HKEY_CURRENT_USER;
3439                         if not regKey.OpenKey( 'Identities', False ) then
3440                                 Exit;
3441                         Identities                      := regKey.ReadString( 'Default User ID' );
3442                         if Identities = '' then
3443                                 Exit;
3444                         if not regKey.OpenKey( Identities + OE_MAIL_PATH, False ) then
3445                                 Exit;
3446                         IndentChar := regKey.ReadInteger( INDENT_CHAR );
3447                         Result := Char( IndentChar ) + ' ';
3448                 except
3449                 end;
3450         finally
3451                 regKey.Free;
3452         end;
3453
3454 end;
3455 //! \92u\8a·\90Ý\92è\83t\83@\83C\83\8b\8eæ\93¾
3456 function TGikoSys.GetReplaceFileName: String;
3457 begin
3458     Result := Setting.GetReplaceFileName;
3459 end;
3460 //! \83v\83\8c\83r\83\85\81[\8ag\92£\82Ì\90Ý\92è\83t\83@\83C\83\8b\8eæ\93¾
3461 function TGikoSys.GetExtpreviewFileName: String;
3462 begin
3463     Result := Setting.GetExtprevieFileName;
3464 end;
3465
3466 //! \83t\83@\83C\83\8b\96¼\82©\82ç\82Ì\83X\83\8c\83b\83h\8dì\90¬\93ú\82Ì\8eæ\93¾
3467 function TGikoSys.GetCreateDateFromName(FileName: String): TDateTime;
3468 var
3469     tmp : String;
3470     unixtime: Int64;  
3471 begin
3472     // \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
3473     tmp := ChangeFileExt(FileName, '');
3474     if AnsiPos('_', tmp) <> 0 then
3475         if AnsiPos('_', tmp) > 9 then
3476             tmp := Copy(tmp, 1, AnsiPos('_', tmp)-1)
3477         else
3478             Delete(tmp, AnsiPos('_', tmp), 1);
3479
3480     if ( Length(tmp) = 9) and ( tmp[1] = '0' ) then
3481         Insert('1', tmp, 1);
3482
3483     unixtime := StrToInt64Def(tmp, ZERO_DATE);
3484     Result := UnixToDateTime(unixtime) + OffsetFromUTC;
3485 end;
3486
3487 procedure TGikoSys.ShowRefCount(msg: String; unk: IUnknown);
3488 var
3489     count : integer;
3490 begin
3491     if not Assigned(unk) then
3492         Exit;
3493
3494 {$IFDEF DEBUG}
3495     try
3496         unk._AddRef;
3497         count := unk._Release;
3498
3499                 Writeln(msg + ' RefCount=' + IntToStr(count));
3500     except
3501                 Writeln(msg + ' RefCount=exception!!');
3502         end;
3503 {$ENDIF}
3504 end;
3505
3506 initialization
3507         GikoSys := TGikoSys.Create;
3508
3509 finalization
3510         if GikoSys <> nil then begin
3511                 FreeAndNil(GikoSys);
3512         end;
3513 end.