OSDN Git Service

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