OSDN Git Service

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