OSDN Git Service

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