OSDN Git Service

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