OSDN Git Service

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