OSDN Git Service

・レスメッセージ中のアドレスにアンカーを自動付加するときにうまく付加できずに化けることがあったので修正。
[gikonavigoeson/gikonavi.git] / GikoSystem.pas
1 unit GikoSystem;
2
3 interface
4
5 uses
6         Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
7         ComCtrls, IniFiles, ShellAPI, ActnList, Math,
8 {$IF Defined(DELPRO) }
9         SHDocVw,
10         MSHTML,
11 {$ELSE}
12         SHDocVw_TLB,
13         MSHTML_TLB,
14 {$IFEND}
15         {HttpApp,} YofUtils, URLMon, IdGlobal, IdURI, {Masks,}
16         Setting, BoardGroup, gzip, Dolib, bmRegExp, AbonUnit;
17
18 type
19         //BBS\83^\83C\83v
20         TGikoBBSType = (gbt2ch);
21         //\83\8d\83O\83^\83C\83v
22         TGikoLogType = (glt2chNew, glt2chOld);
23         //\83\81\83b\83Z\81[\83W\83A\83C\83R\83\93
24         TGikoMessageIcon = (gmiOK, gmiSAD, gmiNG, gmiWhat, gmiNone);
25         //URL\83I\81[\83v\83\93\83u\83\89\83E\83U\83^\83C\83v
26         TGikoBrowserType = (gbtIE, gbtUserApp, gbtAuto);
27
28
29         TStrTokSeparator = set of Char;
30         TStrTokRec = record
31                 Str: string;
32                 Pos: Integer;
33         end;
34
35         //\83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b\83\8c\83R\81[\83h
36         TIndexRec = record
37                 FNo: Integer;
38                 FFileName: string;
39                 FTitle: string;
40                 FCount: Integer;
41                 FSize: Integer;
42 //              FRoundNo: Integer;
43                 FRoundDate: TDateTime;
44                 FLastModified: TDateTime;
45                 FKokomade: Integer;
46                 FNewReceive: Integer;
47                 FMishiyou: Boolean;     //\96¢\8eg\97p
48                 FUnRead: Boolean;
49                 FScrollTop: Integer;
50                 //Index Ver 1.01
51                 FAllResCount: Integer;
52                 FNewResCount: Integer;
53                 FAgeSage: TGikoAgeSage;
54         end;
55
56         //\83T\83u\83W\83F\83N\83g\83\8c\83R\81[\83h
57         TSubjectRec = record
58                 FFileName: string;
59                 FTitle: string;
60                 FCount: Integer;
61         end;
62
63         //\83\8c\83X\83\8c\83R\81[\83h
64         TResRec = record
65                 FTitle: string;
66                 FMailTo: string;
67                 FName: string;
68                 FDateTime: string;
69                 FBody: string;
70                 FType: TGikoLogType;
71         end;
72
73         //URLPath\83\8c\83R\81[\83h
74         TPathRec = record
75                 FBBS: string;                           //BBSID
76                 FKey: string;                           //ThreadID
77                 FSt: Integer;                           //\8aJ\8en\83\8c\83X\94Ô
78                 FTo: Integer;                           //\8fI\97¹\83\8c\83X\94Ô
79                 FFirst: Boolean;                //>>1\82Ì\95\\8e¦
80                 FStBegin: Boolean;      //1\81`\95\\8e¦
81                 FToEnd: Boolean;                //\81`\8dÅ\8cã\82Ü\82Å\95\\8e¦
82                 FDone: Boolean;                 //\90¬\8c÷
83         end;
84
85         TGikoSys = class(TObject)
86         private
87                 { Private \90é\8c¾ }
88                 FSetting: TSetting;
89                 FDolib: TDolib;
90                 FAWKStr: TAWKStr;
91                 FOnlyAHundredRes : Boolean;
92 //              FExitWrite: TStringList;
93 //              function StrToFloatDef(s: string; Default: Double): Double;
94
95         public
96                 { Public \90é\8c¾ }
97                 FAbon : TAbon;
98                 FSelectResFilter : TAbon;
99                 constructor Create;
100
101                 destructor Destroy; override;
102                 property OnlyAHundredRes : Boolean read FOnlyAHundredRes write FOnlyAHundredRes;
103
104 //              function MsgBox(Msg: string; Title: string; Flags: Longint): integer; overload;
105 //              function MsgBox(Handle: THandle; Msg: string; Title: string; Flags: Longint): integer; overload;
106                 function IsNumeric(s: string): boolean;
107                 function IsFloat(s: string): boolean;
108                 function DirectoryExistsEx(const Name: string): Boolean;
109                 function ForceDirectoriesEx(Dir: string): Boolean;
110 //              function GetVersion: string;
111
112                 function GetBoardFileName: string;
113                 function GetCustomBoardFileName: string;
114                 function GetHtmlTempFileName: string;
115                 function GetAppDir: string;
116                 function GetTempFolder: string;
117                 function GetSentFileName: string;
118                 function GetConfigDir: string;
119                 function GetSkinDir: string;
120                 function GetSkinHeaderFileName: string;
121                 function GetSkinFooterFileName: string;
122                 function GetSkinResFileName: string;
123                 function GetSkinNewResFileName: string;
124                 function GetSkinBookmarkFileName: string;
125                 function GetSkinNewmarkFileName: string;
126                 function GetStyleSheetDir: string;
127                 function GetOutBoxFileName: string;
128                 function GetURL(BBSID: string; FileName: string): string;
129                 function GetUserAgent: string;
130
131                 procedure ReadSubjectFile(Board: TBoard);
132                 procedure CreateThreadDat(Board: TBoard);
133                 procedure WriteThreadDat(Board: TBoard);
134                 function ParseIndexLine(Line: string): TIndexRec;
135                 procedure GetFileList(Path: string; Mask: string; List: TStringList; SubDir: Boolean; IsPathAdd: Boolean);
136                 procedure GetDirectoryList(Path: string; Mask: string; List: TStringList; SubDir: Boolean);
137
138                 procedure CreateHTML2(doc: Variant; ThreadItem: TThreadItem; var sTitle: string);
139                 function AddAnchorTag(s: string): string;
140
141                 function DivideSubject(Line: string): TSubjectRec;
142                 function DivideStrLine(Line: string): TResRec;
143
144                 property Setting: TSetting read FSetting write FSetting;
145                 property Dolib: TDolib read FDolib write FDolib;
146
147                 function UrlToID(url: string): string;
148                 function UrlToServer(url: string): string;
149
150                 function StrTokFirst(const s:string; const sep:TStrTokSeparator; var Rec:TStrTokRec):string;
151                 function StrTokNext(const sep:TStrTokSeparator; var Rec:TStrTokRec): string;
152
153                 function GetFileSize(FileName : string) : longint;
154                 function GetFileLineCount(FileName : string): longint;
155                 function Get2chDate(aDate: TDateTime): string;
156                 function IntToDateTime(val: Int64): TDateTime;
157                 function DateTimeToInt(ADate: TDateTime): Integer;
158
159                 function ReadThreadFile(FileName: string; Line: Integer): string;
160
161                 procedure MenuFont(Font: TFont);
162
163                 function RemoveToken(var s:string;delimiter:string):string;
164                 function GetTokenIndex(s: string; delimiter: string; index: Integer): string;
165
166                 function DeleteLink(const s: string): string;
167
168                 function GetShortName(const LongName: string; ALength: integer): string;
169                 function ConvRes(const Body, Bbs, Key,  ParamBBS, ParamKey, ParamStart, ParamTo, ParamNoFirst, ParamTrue : string): string;
170
171                 function ZenToHan(const s: string): string;
172                 function VaguePos(const Substr, S: string): Integer;
173                 function BoolToInt(b: Boolean): Integer;
174                 function IntToBool(i: Integer): Boolean;
175                 function GzipDecompress(ResStream: TStream; ContentEncoding: string): string;
176                 procedure LoadKeySetting(ActionList: TActionList);
177                 procedure SaveKeySetting(ActionList: TActionList);
178                 procedure CreateProcess(const AppPath: string; const Param: string);
179                 procedure OpenBrowser(URL: string; BrowserType: TGikoBrowserType);
180                 function HTMLDecode(const AStr: String): String;
181                 function GetHRefText(s: string): string;
182                 function Is2chHost(Host: string): Boolean;
183                 function Parse2chURL(const url: string; const path: string; const document: string; var BBSID: string; var BBSKey: string): Boolean;
184                 function Parse2chURL2(URL: string): TPathRec;
185                 procedure ParseURI(var URL, Protocol, Host, Path, Document, Port, Bookmark: string);
186                 function GetVersionBuild: Integer;
187
188                 // \83X\83L\83\93\82ð\93Ç\82Ý\8d\9e\82Ý\81A\92l\82ð\92u\8a·\82·\82é
189                 function LoadFromSkin( fileName: string; ThreadItem: TThreadItem; SizeByte: Integer ): string;
190         // \83\8c\83X\82Ì\92l\82ð\92u\8a·\82·\82é
191                 function SkinedRes( skin: string; Res: TResRec; No: string ): string;
192
193         end;
194
195 var
196         GikoSys: TGikoSys;
197 const
198         LENGTH_RESTITLE                 = 40;
199         ZERO_DATE: Integer      = 25569;
200         BETA_VERSION_NAME_E = 'beta';
201         BETA_VERSION_NAME_J = 'ÊÞÀ';
202         BETA_VERSION                            = 44;
203         BETA_VERSION_BUILD      = '';                           //debug\94Å\82È\82Ç
204         APP_NAME                                                = 'gikoNavi';
205
206 implementation
207
208 uses
209         Giko, RoundData, ExternalBoardManager;
210
211 const
212         FOLDER_INDEX_VERSION                                    = '1.01';
213         USER_AGENT                                                                              = 'Monazilla';
214         DEFAULT_NGWORD_FILE_NAME : String = 'NGword.txt';
215         NGWORDs_DIR_NAME : String               = 'NGwords';
216
217 (*************************************************************************
218  *GikoSys\83R\83\93\83X\83g\83\89\83N\83^
219  *************************************************************************)
220 constructor TGikoSys.Create;
221 begin
222         FSetting := TSetting.Create;
223         FDolib := TDolib.Create;
224         FAWKStr := TAWKStr.Create(nil);
225         if DirectoryExists(GetConfigDir) = false then begin
226                 CreateDir(GetConfigDir);
227         end;
228         FAbon := TAbon.Create;
229         FAbon.Setroot(GetConfigDir+NGWORDs_DIR_NAME);
230         FAbon.GoHome;
231         FAbon.ReturnNGwordLineNum := FSetting.ShowNGLinesNum;
232         FAbon.SetNGResAnchor := FSetting.AddResAnchor;
233         FAbon.Deleterlo := FSetting.AbonDeleterlo;
234         FAbon.Replaceul := FSetting.AbonReplaceul;
235         FAbon.AbonPopupRes := FSetting.PopUpAbon;
236
237         FSelectResFilter := TAbon.Create;
238         // \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
239         FSelectResFilter.AbonString := '';
240         //
241         OnlyAHundredRes := FSetting.OnlyAHundredRes;
242 end;
243
244 (*************************************************************************
245  *GikoSys\83f\83X\83g\83\89\83N\83^
246  *************************************************************************)
247 destructor TGikoSys.Destroy;
248 var
249         i: Integer;
250         FileList: TStringList;
251 begin
252         //\83X\83\8c\83b\83h\83f\81[\83^\83t\83@\83C\83\8b\82ð\8dX\90V
253 //      FlashExitWrite;
254
255 //      FExitWrite.Free;
256         FAWKStr.Free;
257         FSetting.Free;
258         FDolib.Free;
259
260         //\83e\83\93\83|\83\89\83\8aHTML\82ð\8dí\8f\9c
261         FileList := TStringList.Create;
262         try
263                 GetFileList(GetTempFolder, '*.html', FileList, False, True);
264                 for i := 0 to FileList.Count - 1 do begin
265                         DeleteFile(FileList[i]);
266                 end;
267         finally
268                 FileList.Free;
269         end;
270         inherited;
271 end;
272
273 (*************************************************************************
274  *\95\8e\9a\97ñ\90\94\8e\9a\83`\83F\83b\83N
275  *************************************************************************)
276 {$HINTS OFF}
277 function TGikoSys.IsNumeric(s: string): boolean;
278 var
279         e: integer;
280         v: integer;
281 begin
282         Val(s, v, e);
283         Result := e = 0;
284 end;
285 {$HINTS ON}
286
287 (*************************************************************************
288  *\95\8e\9a\97ñ\95\82\93®\8f¬\90\94\93_\90\94\8e\9a\83`\83F\83b\83N
289  *************************************************************************)
290 function TGikoSys.IsFloat(s: string): boolean;
291 var
292         v: Extended;
293 begin
294         Result := TextToFloat(PChar(s), v, fvExtended);
295 end;
296
297 (*************************************************************************
298  *\83{\81[\83h\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
299  *************************************************************************)
300 function TGikoSys.GetBoardFileName: string;
301 begin
302         Result := Setting.GetBoardFileName;
303 end;
304
305 (*************************************************************************
306  *\83{\81[\83h\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
307  *************************************************************************)
308 function TGikoSys.GetCustomBoardFileName: string;
309 begin
310         Result := Setting.GetCustomBoardFileName;
311 end;
312
313 (*************************************************************************
314  *\83e\83\93\83|\83\89\83\8a\83t\83H\83\8b\83_\81[\96¼\8eæ\93¾
315  *************************************************************************)
316 function TGikoSys.GetHtmlTempFileName: string;
317 begin
318         Result := Setting.GetHtmlTempFileName;
319 end;
320
321
322 (*************************************************************************
323  *\8eÀ\8ds\83t\83@\83C\83\8b\83t\83H\83\8b\83_\8eæ\93¾
324  *************************************************************************)
325 function TGikoSys.GetAppDir: string;
326 begin
327         Result := Setting.GetAppDir;
328 end;
329
330 (*************************************************************************
331  *TempHtml\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
332  *************************************************************************)
333 function TGikoSys.GetTempFolder: string;
334 begin
335         Result := Setting.GetTempFolder;
336 end;
337
338 (*************************************************************************
339  *sent.ini\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
340  *************************************************************************)
341 function TGikoSys.GetSentFileName: string;
342 begin
343         Result := Setting.GetSentFileName;
344 end;
345
346 (*************************************************************************
347  *outbox.ini\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
348  *************************************************************************)
349 function TGikoSys.GetOutBoxFileName: string;
350 begin
351         Result := Setting.GetOutBoxFileName;
352 end;
353
354 (*************************************************************************
355  *Config\83t\83H\83\8b\83_\8eæ\93¾
356  *************************************************************************)
357 function TGikoSys.GetConfigDir: string;
358 begin
359         Result := Setting.GetConfigDir;
360 end;
361
362 function TGikoSys.GetStyleSheetDir: string;
363 begin
364         Result := Setting.GetStyleSheetDir;
365 end;
366
367 function TGikoSys.GetSkinDir: string;
368 begin
369         Result := Setting.GetSkinDir;
370 end;
371
372 function TGikoSys.GetSkinHeaderFileName: string;
373 begin
374         Result := Setting.GetSkinHeaderFileName;
375 end;
376
377 function TGikoSys.GetSkinFooterFileName: string;
378 begin
379         Result := Setting.GetSkinFooterFileName;
380 end;
381
382 function TGikoSys.GetSkinNewResFileName: string;
383 begin
384         Result := Setting.GetSkinNewResFileName;
385 end;
386
387 function TGikoSys.GetSkinResFileName: string;
388 begin
389         Result := Setting.GetSkinResFileName;
390 end;
391
392 function TGikoSys.GetSkinBookmarkFileName: string;
393 begin
394         Result := Setting.GetSkinBookmarkFileName;
395 end;
396
397 function TGikoSys.GetSkinNewmarkFileName: string;
398 begin
399         Result := Setting.GetSkinNewmarkFileName;
400 end;
401
402 (*************************************************************************
403  *URL\82ð\8dì\90¬(\83R\83s\83y\97p)
404  *************************************************************************)
405 function TGikoSys.GetURL(BBSID: string; FileName: string): string;
406 var
407         Board: TBoard;
408 begin
409         Board := BoardGroup.BBS2ch.GetBoardFromBBSID(BBSID);
410         Result := UrlToServer(Board.URL) + 'test/read.cgi/' + UrlToID(Board.URL) + '/' + ChangeFileExt(FileName, '') + '/l50';
411         //http://teri.2ch.net/test/read.cgi?bbs=accuse&key=974619522&ls=50
412         //http://pc.2ch.net/test/read.cgi/tech/1003664165/l50
413 end;
414
415 // UserAgent\8eæ\93¾
416 function TGikoSys.GetUserAgent: string;
417 begin
418         if Dolib.Connected then begin
419                 Result := Format('%s %s/%s%d%s', [
420                                                                 Dolib.UserAgent,
421                                                                 APP_NAME,
422                                                                 //MAJOR_VERSION,
423                                                                 //MINOR_VERSION,
424                                                                 BETA_VERSION_NAME_E,
425                                                                 BETA_VERSION,
426                                                                 BETA_VERSION_BUILD]);
427         end else begin
428                 Result := Format('%s/%s %s/%s%d%s', [
429                                                                 USER_AGENT,
430                                                                 Dolib.Version,
431                                                                 APP_NAME,
432                                                                 //MAJOR_VERSION,
433                                                                 //MINOR_VERSION,
434                                                                 BETA_VERSION_NAME_E,
435                                                                 BETA_VERSION,
436                                                                 BETA_VERSION_BUILD]);
437         end;
438 end;
439
440 (*************************************************************************
441  *\82Q\82¿\82á\82ñ\82Ë\82é\95û\8e®\8e\9e\8d\8f\8eæ\93¾
442  *************************************************************************)
443 function TGikoSys.Get2chDate(aDate: TDateTime): string;
444 var
445         d1: TDateTime;
446         d2: TDateTime;
447 begin
448         d1 := EncodeDate(1970, 1, 1);
449         d2 := aDate - EncodeTime(9, 0, 0, 0);
450         Result := FloatToStr(Trunc((d2 - d1) * 24 * 60 * 60));
451 end;
452
453
454 function TGikoSys.IntToDateTime(val: Int64): TDateTime;
455 var
456         d1: tdatetime;
457         d2: tdatetime;
458 begin
459         d1 := EncodeDate(1970, 1, 1);
460         d2 := (val * 1000) / (24 * 60 * 60 * 1000);
461         Result := d1 + d2;
462 end;
463
464 function TGikoSys.DateTimeToInt(ADate: TDateTime): Integer;
465 var
466         d: TDateTime;
467         c: Currency;
468 begin
469         d := EncodeDate(1970, 1, 1);
470         c := (ADate - d) * 24 * 60 * 60;
471         Result := Trunc(c);
472 end;
473
474
475 (*************************************************************************
476  *Subject\83t\83@\83C\83\8bRead
477  *************************************************************************)
478 procedure TGikoSys.ReadSubjectFile(Board: TBoard);
479 var
480         ThreadItem: TThreadItem;
481         FileName: string;
482         FileList: TStringList;
483         TmpFileList: TStringList;
484 //      SrchRec: TSearchRec;
485 //      R: integer;
486         Index: Integer;
487         sl: TStringList;
488         i: Integer;
489         Rec: TIndexRec;
490         UnRead: Integer;
491 //      TmpUpdate: Boolean;
492         ini: TMemIniFile;
493         ResRec: TResRec;
494         RoundItem: TRoundItem;
495         idx: Integer;
496         usePlugIn : Boolean;
497 begin
498         Board.Clear;
499         UnRead := 0;
500 //      TmpUpdate := False;
501
502         usePlugIn := Board.IsBoardPlugInAvailable;
503
504         FileName := Board.GetFolderIndexFileName;
505         if not FileExists(FileName) then CreateThreadDat(Board);
506 //      if not FileExists(FileName) then Exit;
507
508         {       R := FindFirst(ExtractFileDir(Board.GetFolderIndexFileName) + '\*.dat', 0, SrchRec);
509                 while R = 0 do begin
510                         FileList.Add(SrchRec.Name);
511                         R := FindNext(SrchRec);
512                 end;
513                 FindClose(SrchRec);}
514
515         FileList := TStringList.Create;
516         FileList.Sorted := True;
517         TmpFileList := TStringList.Create;
518         TmpFileList.Sorted := True;
519
520         //IsLogFile\97pDAT\83t\83@\83C\83\8b\83\8a\83X\83g
521         GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.dat', FileList, False, False);
522
523         //\91O\89ñ\88Ù\8fí\8fI\97¹\8e\9e\97pTmp\83t\83@\83C\83\8b\83\8a\83X\83g
524         GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.tmp', TmpFileList, False, False);
525
526
527         sl := TStringList.Create;
528         try
529                 if FileExists(FileName) then
530                         sl.LoadFromFile(FileName);
531
532                 //\82Q\8ds\96Ú\82©\82ç\81i\82P\8ds\96Ú\82Í\83o\81[\83W\83\87\83\93\81j
533                 for i := 1 to sl.Count - 1 do begin
534                         Rec := ParseIndexLine(sl[i]);
535
536                         if usePlugIn then
537                                 ThreadItem := TThreadItem.Create(
538                                         Board.BoardPlugIn,
539                                         Board.BoardPlugIn.FileName2ThreadURL( DWORD( Board ), Rec.FFileName ) )
540                         else
541                                 ThreadItem := TThreadItem.Create;
542                         ThreadItem.BeginUpdate;
543                         ThreadItem.No := Rec.FNo;
544                         ThreadItem.FileName := Rec.FFileName;
545                         ThreadItem.Title := Rec.FTitle;
546                         ThreadItem.Count := Rec.FCount;
547                         ThreadItem.Size := Rec.FSize;
548 //                      ThreadItem.RoundNo := Rec.FRoundNo;
549                         ThreadItem.RoundDate := Rec.FRoundDate;
550                         ThreadItem.LastModified := Rec.FLastModified;
551                         ThreadItem.Kokomade := Rec.FKokomade;
552                         ThreadItem.NewReceive := Rec.FNewReceive;
553 //                      ThreadItem.Round := Rec.FRound;
554                         ThreadItem.UnRead := Rec.FUnRead;
555                         ThreadItem.ScrollTop := Rec.FScrollTop;
556                         ThreadItem.AllResCount := Rec.FAllResCount;
557                         ThreadItem.NewResCount := Rec.FNewResCount;
558                         ThreadItem.AgeSage := Rec.FAgeSage;
559                         ThreadItem.ParentBoard := Board;
560
561                         //IsLogFile\83`\83F\83b\83N
562                         ThreadItem.IsLogFile := False;
563                         if FileList.Count <> 0 then begin
564                                 if FileList.Find(ThreadItem.FileName, Index) then begin
565                                         ThreadItem.IsLogFile := True;
566                                         FileList.Delete(Index);
567                                 end;
568                         end;
569
570                         //\8f\84\89ñ\83\8a\83X\83g\82É\91\8dÝ\82µ\82½\82ç\8f\84\89ñ\83t\83\89\83O\83Z\83b\83g
571                         if ThreadItem.IsLogFile then begin
572                                 idx := RoundList.Find(ThreadItem);
573                                 if idx <> -1 then begin
574                                         RoundItem := RoundList.Items[idx, grtItem];
575                                         ThreadItem.RoundName := RoundItem.RoundName;
576                                         ThreadItem.Round := True;
577                                 end;
578                         end;
579
580                         //\91O\89ñ\88Ù\8fí\8fI\97¹\8e\9e\83`\83F\83b\83N
581                         if TmpFileList.Count <> 0 then begin
582                                 if TmpFileList.Find(ChangeFileExt(ThreadItem.FileName, '.tmp'), Index) then begin
583                                         ini := TMemIniFile.Create(ChangeFileExt(ThreadItem.GetThreadFileName, '.tmp'));
584                                         try
585                                                 ThreadItem.RoundDate := ini.ReadDateTime('Setting', 'RoundDate', ZERO_DATE);
586                                                 ThreadItem.LastModified := ini.ReadDateTime('Setting', 'LastModified', ZERO_DATE);
587                                                 ThreadItem.Size := ini.ReadInteger('Setting', 'Size', 0);
588                                                 ThreadItem.Count := ini.ReadInteger('Setting', 'Count', 0);
589                                                 ThreadItem.NewReceive := ini.ReadInteger('Setting', 'NewReceive', 0);
590                                                 ThreadItem.Round := ini.ReadBool('Setting', 'Round', False);
591                                                 ThreadItem.UnRead := False;//ini.ReadBool('Setting', 'UnRead', False);
592                                                 ThreadItem.ScrollTop := ini.ReadInteger('Setting', 'ScrollTop', 0);
593                                                 ThreadItem.AllResCount := ini.ReadInteger('Setting', 'AllResCount', 0);
594                                                 ThreadItem.NewResCount := ini.ReadInteger('Setting', 'NewResCount', 0);
595                                                 ThreadItem.AgeSage := TGikoAgeSage(ini.ReadInteger('Setting', 'AgeSage', Ord(gasNone)));
596                                         finally
597                                                 ini.Free;
598                                         end;
599                                         TmpFileList.Delete(Index);
600                                 end;
601                         end;
602
603                         ThreadItem.EndUpdate;
604                         Board.Add(ThreadItem);
605
606 //                      if (ThreadItem.IsLogFile) and (ThreadItem.Count > ThreadItem.Kokomade) then
607                         if (ThreadItem.IsLogFile) and (ThreadItem.UnRead) then
608                                 Inc(UnRead);
609                 end;
610
611                 if UnRead <> Board.UnRead then
612                         Board.UnRead := UnRead;
613
614                 //\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
615                 for i := 0 to FileList.Count - 1 do begin
616                         FileName := ExtractFileDir(Board.GetFolderIndexFileName) + '\' + FileList[i];
617
618                         ResRec := DivideStrLine(ReadThreadFile(FileName, 1));
619                         if usePlugIn then
620                                 ThreadItem := TThreadItem.Create(
621                                         Board.BoardPlugIn,
622                                         Board.BoardPlugIn.FileName2ThreadURL( DWORD( Board ), Rec.FFileName ) )
623                         else
624                                 ThreadItem := TThreadItem.Create;
625                         ThreadItem.No := Board.Count + 1;
626                         ThreadItem.FileName := FileList[i];
627                         ThreadItem.Title := ResRec.FTitle;
628                         ThreadItem.Count := GetFileLineCount(FileName);
629                         ThreadItem.AllResCount := ThreadItem.Count;
630                         ThreadItem.NewResCount := 0;
631                         ThreadItem.Size := 0;
632                         ThreadItem.RoundDate := ZERO_DATE;
633                         ThreadItem.LastModified := ZERO_DATE;
634                         ThreadItem.Kokomade := -1;
635                         ThreadItem.NewReceive := 0;
636                         ThreadItem.ParentBoard := Board;
637                         ThreadItem.IsLogFile := True;
638                         ThreadItem.Round := False;
639                         ThreadItem.UnRead := False;
640                         ThreadItem.ScrollTop := 0;
641                         ThreadItem.AgeSage := gasNone;
642                         Board.Add(ThreadItem);
643                 end;
644         finally
645                 sl.Free;
646         end;
647         FileList.Free;
648         TmpFileList.Free;
649         Board.IsThreadDatRead := True;
650 end;
651
652 (*************************************************************************
653  *\83X\83\8c\83b\83h\83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b(Folder.idx)\8dì\90¬
654  *************************************************************************)
655 procedure TGikoSys.CreateThreadDat(Board: TBoard);
656 var
657         i: integer;
658         s: string;
659         SubjectList: TStringList;
660         sl: TStringList;
661         Rec: TSubjectRec;
662         FileName: string;
663         cnt: Integer;
664 begin
665         if not FileExists(Board.GetSubjectFileName) then Exit;
666         FileName := Board.GetFolderIndexFileName;
667
668         SubjectList := TStringList.Create;
669         try
670                 SubjectList.LoadFromFile(Board.GetSubjectFileName);
671                 sl := TStringList.Create;
672                 try
673                         cnt := 1;
674                         sl.Add(FOLDER_INDEX_VERSION);
675                         for i := 0 to SubjectList.Count - 1 do begin
676                                 Rec := DivideSubject(SubjectList[i]);
677
678                                 if (Trim(Rec.FFileName) = '') or (Trim(Rec.FTitle) = '') then
679                                         Continue;
680
681                                 s := Format('%x', [cnt]) + #1                                   //\94Ô\8d\86
682                                          + Rec.FFileName + #1                                                           //\83t\83@\83C\83\8b\96¼
683                                          + Rec.FTitle + #1                                                                      //\83^\83C\83g\83\8b
684                                          + Format('%x', [Rec.FCount]) + #1      //\83J\83E\83\93\83g
685                                          + Format('%x', [0]) + #1                                               //size
686                                          + Format('%x', [0]) + #1                                               //RoundDate
687                                          + Format('%x', [0]) + #1                                               //LastModified
688                                          + Format('%x', [0]) + #1                                               //Kokomade
689                                          + Format('%x', [0]) + #1                                               //NewReceive
690                                          + '0' + #1                                                                                             //\96¢\8eg\97p
691                                          + Format('%x', [0]) + #1                                               //UnRead
692                                          + Format('%x', [0]) + #1                                               //ScrollTop
693                                          + Format('%x', [Rec.FCount]) + #1      //AllResCount
694                                          + Format('%x', [0]) + #1                                               //NewResCount
695                                          + Format('%x', [0]);                                                           //AgeSage
696
697                                 sl.Add(s);
698                                 inc(cnt);
699                         end;
700                         sl.SaveToFile(FileName);
701                 finally
702                         sl.Free;
703                 end;
704         finally
705                 SubjectList.Free;
706         end;
707 end;
708
709 (*************************************************************************
710  *\83X\83\8c\83b\83h\83C\83\93\83f\83b\83N\83X(Thread.dat)\8f\91\82«\8d\9e\82Ý
711  *Public
712  *************************************************************************)
713 procedure TGikoSys.WriteThreadDat(Board: TBoard);
714 //const
715 //      Values: array[Boolean] of string = ('0', '1');
716 var
717         i: integer;
718         FileName: string;
719         sl: TStringList;
720         s: string;
721         FileList: TStringList;
722 begin
723         if not Board.IsThreadDatRead then
724                 Exit;
725         FileName := Board.GetFolderIndexFileName;
726         ForceDirectoriesEx(Board.ParentCategory.ParentBBS2ch.GetLogFolder + Board.BBSID);
727
728         sl := TStringList.Create;
729         try
730                 sl.Add(FOLDER_INDEX_VERSION);
731                 for i := 0 to Board.Count - 1 do begin
732                         if Board.Items[i].No = 0 then
733                                 Board.Items[i].No := i + 1;
734
735                         s := Format('%x', [Board.Items[i].No]) + #1
736                                  + Board.Items[i].FileName + #1
737                                  + Board.Items[i].Title + #1
738                                  + Format('%x', [Board.Items[i].Count]) + #1
739                                  + Format('%x', [Board.Items[i].Size]) + #1
740                                  + Format('%x', [DateTimeToInt(Board.Items[i].RoundDate)]) + #1
741                                  + Format('%x', [DateTimeToInt(Board.Items[i].LastModified)]) + #1
742                                  + Format('%x', [Board.Items[i].Kokomade]) + #1
743                                  + Format('%x', [Board.Items[i].NewReceive]) + #1
744                                  + '0' + #1     //\96¢\8eg\97p
745                                  + Format('%x', [BoolToInt(Board.Items[i].UnRead)]) + #1
746                                  + Format('%x', [Board.Items[i].ScrollTop]) + #1
747                                  + Format('%x', [Board.Items[i].AllResCount]) + #1
748                                  + Format('%x', [Board.Items[i].NewResCount]) + #1
749                                  + Format('%x', [Ord(Board.Items[i].AgeSage)]);
750
751                         sl.Add(s);
752                 end;
753
754                 sl.SaveToFile(FileName);
755
756                 FileList := TStringList.Create;
757                 try
758                         GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.tmp', FileList, False, True);
759                         for i := 0 to FileList.Count - 1 do begin
760                                 DeleteFile(FileList[i]);
761                         end;
762                 finally
763                         FileList.Free;
764                 end;
765         finally
766                 sl.Free;
767         end;
768 end;
769
770 function TGikoSys.ParseIndexLine(Line: string): TIndexRec;
771 var
772         s: string;
773         i: Integer;
774 begin
775         for i := 0 to 14 do begin
776                 s := GetTokenIndex(Line, #1, i);
777                 case i of
778                         0: Result.FNo := StrToIntDef('$' + s, 0);
779                         1: Result.FFileName := s;
780                         2: Result.FTitle := s;
781                         3: Result.FCount := StrToIntDef('$' + s, 0);
782                         4: Result.FSize := StrToIntDef('$' + s, 0);
783                         5: Result.FRoundDate := IntToDateTime(StrToIntDef('$' + s, ZERO_DATE));
784                         6: Result.FLastModified := IntToDateTime(StrToIntDef('$' + s, ZERO_DATE));
785                         7: Result.FKokomade := StrToIntDef('$' + s, -1);
786                         8: Result.FNewReceive := StrToIntDef('$' + s, 0);
787                         9: ;    //\96¢\8eg\97p
788                         10: Result.FUnRead := IntToBool(StrToIntDef('$' + s, 0));
789                         11: Result.FScrollTop := StrToIntDef('$' + s, 0);
790                         12: Result.FAllResCount := StrToIntDef('$' + s, 0);
791                         13: Result.FNewResCount := StrToIntDef('$' + s, 0);
792                         14: Result.FAgeSage := TGikoAgeSage(StrToIntDef('$' + s, 0));
793                 end;
794         end;
795 end;
796
797 //\8ew\92è\83t\83H\83\8b\83_\93à\82Ì\8ew\92è\83t\83@\83C\83\8b\88ê\97\97\82ð\8eæ\93¾\82·\82é
798 // ListFiles('c:\', '*.txt', list, True);
799 procedure TGikoSys.GetFileList(Path: string; Mask: string; List: TStringList; SubDir: Boolean; IsPathAdd: Boolean);
800 var
801         rc: Integer;
802         SearchRec : TSearchRec;
803         s: string;
804 begin
805         Path := IncludeTrailingPathDelimiter(Path);
806         rc := FindFirst(Path + '*.*', faAnyfile, SearchRec);
807         try
808                 while rc = 0 do begin
809                         if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then begin
810                                 s := Path + SearchRec.Name;
811                                 //if (SearchRec.Attr and faDirectory > 0) then
812                                 //      s := IncludeTrailingPathDelimiter(s)
813
814                                 if (SearchRec.Attr and faDirectory = 0) and (MatchesMask(s, Mask)) then
815                                         if IsPathAdd then
816                                                 List.Add(s)
817                                         else
818                                                 List.Add(SearchRec.Name);
819                                 if SubDir and (SearchRec.Attr and faDirectory > 0) then
820                                         GetFileList(s, Mask, List, True, IsPathAdd);
821                         end;
822                         rc := FindNext(SearchRec);
823                 end;
824         finally
825                 SysUtils.FindClose(SearchRec);
826         end;
827 end;
828
829 //\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é
830 procedure TGikoSys.GetDirectoryList(Path: string; Mask: string; List: TStringList; SubDir: Boolean);
831 var
832         rc: Integer;
833         SearchRec : TSearchRec;
834         s: string;
835 begin
836         Path := IncludeTrailingPathDelimiter(Path);
837         rc := FindFirst(Path + '*.*', faDirectory, SearchRec);
838         try
839                 while rc = 0 do begin
840                         if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then begin
841                                 s := Path + SearchRec.Name;
842                                 //if (SearchRec.Attr and faDirectory > 0) then
843                                 //      s := IncludeTrailingPathDelimiter(s)
844
845                                 if (SearchRec.Attr and faDirectory > 0) and (MatchesMask(s, Mask)) then
846                                         List.Add( IncludeTrailingPathDelimiter( s ) );
847                                 if SubDir and (SearchRec.Attr and faDirectory > 0) then
848                                         GetDirectoryList(s, Mask, List, True);
849                         end;
850                         rc := FindNext(SearchRec);
851                 end;
852         finally
853                 SysUtils.FindClose(SearchRec);
854         end;
855 end;
856
857 // \83X\83L\83\93\82ð\93Ç\82Ý\8d\9e\82Ý\81A\92l\82ð\92u\8a·\82·\82é
858 function TGikoSys.LoadFromSkin(
859         fileName: string;
860         ThreadItem: TThreadItem;
861         SizeByte: Integer
862 ): string;
863 var
864         Skin: TStringList;
865 begin
866
867         Skin := TStringList.Create;
868         try
869                 if FileExists( fileName ) then begin
870                         Skin.LoadFromFile( fileName );
871
872                         // \82â\82è\82©\82½\82ª\8bê\82µ\82¢\82¯\82Ç\81A\83I\83v\83V\83\87\83\93\83_\83C\83A\83\8d\83O\82Ì\83v\83\8c\83r\83\85\81[\97p try
873                         try
874                                 if ThreadItem.ParentBoard <> nil then
875                                         if ThreadItem.ParentBoard.ParentCategory <> nil then
876                                                 Skin.Text := StringReplace( Skin.Text, '<BBSNAME/>', ThreadItem.ParentBoard.ParentCategory.ParentBBS2ch.Title, [rfReplaceAll] );
877                                 Skin.Text := StringReplace( Skin.Text, '<THREADURL/>', ThreadItem.URL, [rfReplaceAll] );
878                         except end;
879                         Skin.Text := StringReplace( Skin.Text, '<BOARDNAME/>', ThreadItem.ParentBoard.Title, [rfReplaceAll] );
880                         Skin.Text := StringReplace( Skin.Text, '<BOARDURL/>', ThreadItem.ParentBoard.URL, [rfReplaceAll] );
881                         Skin.Text := StringReplace( Skin.Text, '<THREADNAME/>', ThreadItem.Title, [rfReplaceAll] );
882                         Skin.Text := StringReplace( Skin.Text, '<SKINPATH/>', Setting.CSSFileName, [rfReplaceAll] );
883                         Skin.Text := StringReplace( Skin.Text, '<GETRESCOUNT/>', IntToStr( ThreadItem.NewReceive - 1 ), [rfReplaceAll] );
884                         Skin.Text := StringReplace( Skin.Text, '<NEWRESCOUNT/>', IntToStr( ThreadItem.NewResCount ), [rfReplaceAll] );
885                         Skin.Text := StringReplace( Skin.Text, '<ALLRESCOUNT/>', IntToStr( ThreadItem.AllResCount ), [rfReplaceAll] );
886
887                         Skin.Text := StringReplace( Skin.Text, '<NEWDATE/>',
888                         FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate), [rfReplaceAll] );
889                         Skin.Text := StringReplace( Skin.Text, '<SIZEKB/>', IntToStr( Floor( SizeByte / 1024 ) ), [rfReplaceAll] );
890                         Skin.Text := StringReplace( Skin.Text, '<SIZE/>', IntToStr( SizeByte ), [rfReplaceAll] );
891
892                         //----- \82Æ\82è\82 \82¦\82¸\82©\82¿\82ã\81`\82µ\82á\8cÝ\8a·\97p\81B\83R\83\81\83\93\83g\83A\83E\83g\82µ\82Ä\82à\82æ\82µ
893                         // \82â\82è\82©\82½\82ª\8bê\82µ\82¢\82¯\82Ç\81A\83I\83v\83V\83\87\83\93\83_\83C\83A\83\8d\83O\82Ì\83v\83\8c\83r\83\85\81[\97p try
894                         try
895                                 if ThreadItem.ParentBoard <> nil then
896                                         if ThreadItem.ParentBoard.ParentCategory <> nil then
897                                                 Skin.Text := StringReplace( Skin.Text, '&BBSNAME', ThreadItem.ParentBoard.ParentCategory.ParentBBS2ch.Title, [rfReplaceAll] );
898                                 Skin.Text := StringReplace( Skin.Text, '&THREADURL', ThreadItem.URL, [rfReplaceAll] );
899                         except end;
900                         Skin.Text := StringReplace( Skin.Text, '&BOARDNAME', ThreadItem.ParentBoard.Title, [rfReplaceAll] );
901                         Skin.Text := StringReplace( Skin.Text, '&BOARDURL', ThreadItem.ParentBoard.URL, [rfReplaceAll] );
902                         Skin.Text := StringReplace( Skin.Text, '&THREADNAME', ThreadItem.Title, [rfReplaceAll] );
903                         Skin.Text := StringReplace( Skin.Text, '&SKINPATH', Setting.CSSFileName, [rfReplaceAll] );
904                         Skin.Text := StringReplace( Skin.Text, '&GETRESCOUNT', IntToStr( ThreadItem.NewReceive - 1 ), [rfReplaceAll] );
905                         Skin.Text := StringReplace( Skin.Text, '&NEWRESCOUNT', IntToStr( ThreadItem.NewResCount ), [rfReplaceAll] );
906                         Skin.Text := StringReplace( Skin.Text, '&ALLRESCOUNT', IntToStr( ThreadItem.AllResCount ), [rfReplaceAll] );
907
908                         Skin.Text := StringReplace( Skin.Text, '&NEWDATE',
909                                         FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate), [rfReplaceAll] );
910                         Skin.Text := StringReplace( Skin.Text, '&SIZEKB', IntToStr( Floor( SizeByte / 1024 ) ), [rfReplaceAll] );
911                         Skin.Text := StringReplace( Skin.Text, '&SIZE', IntToStr( SizeByte ), [rfReplaceAll] );
912                         //----- \82±\82±\82Ü\82Å
913                 end;
914                 Result := Skin.Text;
915         finally
916                 Skin.Free;
917         end;
918 end;
919
920 // \83\8c\83X\82Ì\92l\82ð\92u\8a·\82·\82é
921 function TGikoSys.SkinedRes(
922         skin: string;
923         Res: TResRec;
924         No: string
925 ): string;
926 begin
927
928         try
929                 Skin := StringReplace( Skin, '<NUMBER/>',
930                         '<a href="menu:' + No + '" name="' + No + '">' + No + '</a>', [rfReplaceAll] );
931                 Skin := StringReplace( Skin, '<PLAINNUMBER/>', No, [rfReplaceAll] );
932                 Skin := StringReplace( Skin, '<NAME/>', '<b>' + Res.FName + '</b>', [rfReplaceAll] );
933                 Skin := StringReplace( Skin, '<MAILNAME/>',
934                         '<a href="mailo:' + Res.FMailTo + '"><b>' + Res.FName + '</b></a>', [rfReplaceAll] );
935                 Skin := StringReplace( Skin, '<MAIL/>', Res.FMailTo, [rfReplaceAll] );
936                 Skin := StringReplace( Skin, '<DATE/>', Res.FDateTime, [rfReplaceAll] );
937                 Skin := StringReplace( Skin, '<MESSAGE/>', Res.FBody, [rfReplaceAll] );
938
939                 //----- \82©\82¿\82ã\81`\82µ\82á\8cÝ\8a·\97p\81B\83R\83\81\83\93\83g\83A\83E\83g\82µ\82Ä\82à\82æ\82µ
940                 Skin := StringReplace( Skin, '&NUMBER',
941                         '<a href="menu:' + No + '" name="' + No + '">' + No + '</a>', [rfReplaceAll] );
942                 Skin := StringReplace( Skin, '&PLAINNUMBER', No, [rfReplaceAll] );
943                 Skin := StringReplace( Skin, '&NAME', '<b>' + Res.FName + '</b>', [rfReplaceAll] );
944                 Skin := StringReplace( Skin, '&MAILNAME',
945                         '<a href="mailo:' + Res.FMailTo + '"><b>' + Res.FName + '</b></a>', [rfReplaceAll] );
946                 Skin := StringReplace( Skin, '&MAIL', Res.FMailTo, [rfReplaceAll] );
947                 Skin := StringReplace( Skin, '&DATE', Res.FDateTime, [rfReplaceAll] );
948                 Skin := StringReplace( Skin, '&MESSAGE', Res.FBody, [rfReplaceAll] );
949                 //----- \82±\82±\82Ü\82Å
950
951                 Result := Skin;
952         finally
953         end;
954
955 end;
956
957 procedure TGikoSys.CreateHTML2(doc: Variant; ThreadItem: TThreadItem; var sTitle: string);
958 var
959         i: integer;
960         No: string;
961         //bufList : TStringList;
962         ReadList: TStringList;
963         SaveList: TStringList;
964         CSSFileName: string;
965         BBSID: string;
966         FileName: string;
967         NewReceiveNo: Integer;
968         Res: TResRec;
969         boardPlugIn : TBoardPlugIn;
970
971         UserOptionalStyle: string;
972         SkinHeader: string;
973         SkinNewRes: string;
974         SkinRes: string;
975         SizeByte: Integer;
976
977         function LoadSkin( fileName: string ): string;
978         begin
979                 Result := LoadFromSkin( fileName, ThreadItem, SizeByte );
980         end;
981         function ReplaceRes( skin: string ): string;
982         begin
983                 Result := SkinedRes( skin, Res, No );
984         end;
985 begin
986         if ThreadItem <> nil then begin
987                 if ThreadItem.IsBoardPlugInAvailable then begin
988                         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
989                         boardPlugIn             := ThreadItem.BoardPlugIn;
990                         NewReceiveNo    := ThreadItem.NewReceive;
991
992                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
993                         if Length( GikoSys.Setting.BrowserFontName ) > 0 then
994                                 UserOptionalStyle := UserOptionalStyle +
995                                                                 'font-family:"' + GikoSys.Setting.BrowserFontName + '";';
996                         if GikoSys.Setting.BrowserFontSize <> 0 then
997                                 UserOptionalStyle := UserOptionalStyle +
998                                                                 'font-size:' + IntToStr( GikoSys.Setting.BrowserFontSize ) + 'pt;';
999                         if GikoSys.Setting.BrowserFontColor <> -1 then
1000                                 UserOptionalStyle := UserOptionalStyle +
1001                                                                 'color:#' + IntToHex( GikoSys.Setting.BrowserFontColor, 6 ) + ';';
1002                         if GikoSys.Setting.BrowserBackColor <> -1 then
1003                                 UserOptionalStyle := UserOptionalStyle +
1004                                                                 'background-color:#' + IntToHex( GikoSys.Setting.BrowserBackColor, 6 ) + ';';
1005                         case GikoSys.Setting.BrowserFontBold of
1006                                 -1: UserOptionalStyle := UserOptionalStyle + 'font-weight:normal;';
1007                                 1: UserOptionalStyle := UserOptionalStyle + 'font-weight:bold;';
1008                         end;
1009                         case GikoSys.Setting.BrowserFontItalic of
1010                                 -1: UserOptionalStyle := UserOptionalStyle + 'font-style:normal;';
1011                                 1: UserOptionalStyle := UserOptionalStyle + 'font-style:italic;';
1012                         end;
1013
1014                         SaveList := TStringList.Create;
1015                         try
1016                                 doc.open;
1017                                 // \95\8e\9a\83R\81[\83h\82Í\83v\83\89\83O\83C\83\93\82É\94C\82¹\82é
1018                                 // doc.charset := 'Shift_JIS';
1019                                 threadItem.SizeByte := 0;
1020
1021                                 // \83w\83b\83_
1022                                 SaveList.Add( boardPlugIn.GetHeader( DWORD( threadItem ),
1023                                         '<style type="text/css">body {' + UserOptionalStyle + '}</style>' ) );
1024
1025                                 for i := 0 to threadItem.Count - 1 do begin
1026                                         if (OnlyAHundredRes = true) and ( i <> 0 ) and ( (threadItem.Count-i) > 101 ) then begin
1027                                                 Continue;
1028                                         end;
1029
1030                                         // \90V\92\85\83}\81[\83N
1031                                         if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
1032                                                 try
1033                                                         if GikoSys.Setting.UseSkin then begin
1034                                                                 SaveList.Add( LoadSkin( GetSkinNewmarkFileName ) );
1035                                                         end else if GikoSys.Setting.UseCSS then begin
1036                                                                 SaveList.Add('<a name="new"></a><div class="new">\90V\92\85\83\8c\83X <span class="newdate">' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</span></div>');
1037                                                         end else begin
1038                                                                 SaveList.Add('</dl>');
1039                                                                 SaveList.Add('<a name="new"></a>');
1040                                                                 SaveList.Add('<table width="100%" bgcolor="#3333CC" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#6666FF" valign="middle"><font size="-1" color="#ffffff"><b>\90V\92\85\83\8c\83X ' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</b></font></td></tr></table>');
1041                                                                 SaveList.Add('<dl>');
1042                                                         end;
1043                                                 except
1044                                                         SaveList.Add( '<a name="new"></a>' );
1045                                                 end;
1046                                         end;
1047
1048                                         // \83\8c\83X
1049                                         SaveList.Add( boardPlugIn.GetRes( DWORD( threadItem ), i + 1 ) );
1050
1051                                         if ThreadItem.Kokomade = (i + 1) then begin
1052                                                 // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾
1053                                                 try
1054                                                         if GikoSys.Setting.UseSkin then begin
1055                                                                 SaveList.Add( LoadSkin( GetSkinBookmarkFileName ) );
1056                                                         end else if GikoSys.Setting.UseCSS then begin
1057                                                                 SaveList.Add('<a name="koko"></a><div class="koko">\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</div>');
1058                                                         end else begin
1059                                                                 SaveList.Add('</dl>');
1060                                                                 SaveList.Add('<a name="koko"></a><table width="100%" bgcolor="#55AA55" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#77CC77" valign="middle"><font size="-1" color="#ffffff"><b>\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</b></font></td></tr></table>');
1061                                                                 SaveList.Add('<dl>');
1062                                                         end;
1063                                                 except
1064                                                         SaveList.Add( '<a name="koko"></a>' );
1065                                                 end;
1066                                         end;
1067
1068                                         threadItem.SizeByte := threadItem.SizeByte + Length( SaveList.Text );
1069                                         doc.Write(SaveList.Text);
1070                                         SaveList.Clear;
1071                                 end;
1072
1073                                 threadItem.SizeByte := threadItem.SizeByte + Length( SaveList.Text );
1074
1075                                 // \83X\83L\83\93(\83t\83b\83^)
1076                                 SaveList.Add( boardPlugIn.GetFooter( DWORD( threadItem ), '<a name="bottom"></a>' ) );
1077
1078                                 doc.Write(SaveList.Text);
1079                         finally
1080                                 SaveList.Free;
1081                                 doc.Close;
1082                         end;
1083
1084                         Exit;
1085                 end;
1086         end;
1087         ShortDayNames[1] := '\93ú';               ShortDayNames[2] := '\8c\8e';
1088         ShortDayNames[3] := '\89Î';               ShortDayNames[4] := '\90\85';
1089         ShortDayNames[5] := '\96Ø';               ShortDayNames[6] := '\8bà';
1090         ShortDayNames[7] := '\93y';
1091         SizeByte := 0;
1092         BBSID := ThreadItem.ParentBoard.BBSID;
1093         NewReceiveNo := ThreadItem.NewReceive;
1094         ReadList := TStringList.Create;
1095         try
1096                 if ThreadItem.IsLogFile then begin
1097                         FileName := ThreadItem.GetThreadFileName;
1098                         ReadList.LoadFromFile(FileName);
1099                         FAbon.IndividualAbon(ReadList, ChangeFileExt(FileName,'.NG'));
1100                         FAbon.Execute(ReadList);                //       \82 \82Ú\81`\82ñ\82µ\82Ä
1101                         FSelectResFilter.Execute(ReadList); //\83\8c\83X\82Ì\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\82·\82é
1102                         Res := DivideStrLine(ReadList[0]);
1103                         Res.FTitle := StringReplace(Res.FTitle, '\81\97\81M', ',', [rfReplaceAll]);
1104                         sTitle := Res.FTitle;
1105                 end else begin
1106                         sTitle := StringReplace(ThreadItem.Title, '\81\97\81M', ',', [rfReplaceAll]);
1107                 end;
1108                 SaveList := TStringList.Create;
1109                 try
1110                         doc.open;
1111                         doc.charset := 'Shift_JIS';
1112
1113                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1114                         if Length( GikoSys.Setting.BrowserFontName ) > 0 then
1115                                 UserOptionalStyle := UserOptionalStyle +
1116                                                                 'font-family:"' + GikoSys.Setting.BrowserFontName + '";';
1117                         if GikoSys.Setting.BrowserFontSize <> 0 then
1118                                 UserOptionalStyle := UserOptionalStyle +
1119                                                                 'font-size:' + IntToStr( GikoSys.Setting.BrowserFontSize ) + 'pt;';
1120                         if GikoSys.Setting.BrowserFontColor <> -1 then
1121                                 UserOptionalStyle := UserOptionalStyle +
1122                                                                 'color:#' + IntToHex( GikoSys.Setting.BrowserFontColor, 6 ) + ';';
1123                         if GikoSys.Setting.BrowserBackColor <> -1 then
1124                                 UserOptionalStyle := UserOptionalStyle +
1125                                                                 'background-color:#' + IntToHex( GikoSys.Setting.BrowserBackColor, 6 ) + ';';
1126                         case GikoSys.Setting.BrowserFontBold of
1127                                 -1: UserOptionalStyle := UserOptionalStyle + 'font-weight:normal;';
1128                                 1: UserOptionalStyle := UserOptionalStyle + 'font-weight:bold;';
1129                         end;
1130                         case GikoSys.Setting.BrowserFontItalic of
1131                                 -1: UserOptionalStyle := UserOptionalStyle + 'font-style:normal;';
1132                                 1: UserOptionalStyle := UserOptionalStyle + 'font-style:italic;';
1133                         end;
1134
1135                         CSSFileName := GetStyleSheetDir + Setting.CSSFileName;
1136                         if GikoSys.Setting.UseSkin then begin
1137                                 // \83X\83L\83\93\8eg\97p
1138                                 // \83X\83L\83\93\82Ì\90Ý\92è
1139                                 try
1140                                         SkinHeader := LoadSkin( GetSkinHeaderFileName );
1141                                         if Length( UserOptionalStyle ) > 0 then
1142                                                 SkinHeader := StringReplace( SkinHeader, '</head>',
1143                                                         '<style type="text/css">body {' + UserOptionalStyle + '}</style></head>', [rfReplaceAll] );
1144                                         SaveList.Add( SkinHeader );
1145                                 except
1146                                 end;
1147                                 try
1148                                         SkinNewRes := LoadSkin( GetSkinNewResFileName );
1149                                 except
1150                                                                 end;
1151                                 try
1152                                         SkinRes := LoadSkin( GetSkinResFileName );
1153                                 except
1154                                 end;
1155
1156                                 SaveList.Add('<a name="top"></a>');
1157
1158                                 for i := 0 to ReadList.Count - 1 do begin
1159                                         if (OnlyAHundredRes = true) and ( i <> 0 ) and ( (ReadList.Count-i) > 101 ) then begin
1160                                                 Continue;
1161                                         end;
1162                                         if (Trim(ReadList[i]) <> '') then begin
1163                                                 No := IntToStr(i + 1);
1164
1165                                                 Res := DivideStrLine(ReadList[i]);
1166                                                 Res.FBody := ConvRes(Res.FBody, ThreadItem.ParentBoard.BBSID, ChangeFileExt(ThreadItem.FileName, ''), 'bbs', 'key', 'st', 'to', 'nofirst', 'true');
1167
1168                                                 if Res.FType = glt2chOld then begin
1169                                                         Res.FMailTo := StringReplace(Res.FMailTo, '\81\97\81M', ',', [rfReplaceAll]);
1170                                                         Res.FName := StringReplace(Res.FName, '\81\97\81M', ',', [rfReplaceAll]);
1171                                                         Res.FBody := StringReplace(Res.FBody, '\81\97\81M', ',', [rfReplaceAll]);
1172                                                 end;
1173
1174                                                 Res.FBody := AddAnchorTag(Res.FBody);
1175                                                 if Res.FName = '' then
1176                                                         Res.FName := '&nbsp;';
1177
1178                                                 // \90V\92\85\83}\81[\83N
1179                                                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
1180                                                         try
1181                                                                 SaveList.Add( LoadSkin( GetSkinNewmarkFileName ) );
1182                                                         except
1183                                                                 SaveList.Add( '<a name="new"></a>' );
1184                                                         end;
1185                                                 end;
1186                                                 try
1187                                                         if NewReceiveNo <= (i + 1) then
1188                                                                 // \90V\92\85\83\8c\83X
1189                                                                 SaveList.Add( ReplaceRes( SkinNewRes ) )
1190                                                         else
1191                                                                 // \92Ê\8fí\82Ì\83\8c\83X
1192                                                                 SaveList.Add( ReplaceRes( SkinRes ) );
1193                                                 except
1194                                                 end;
1195                                                 if ThreadItem.Kokomade = (i + 1) then begin
1196                                                         // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾
1197                                                         try
1198                                                                 SaveList.Add( LoadSkin( GetSkinBookmarkFileName ) );
1199                                                         except
1200                                                                 SaveList.Add( '<a name="koko"></a>' );
1201                                                         end;
1202                                                 end;
1203                                         end;
1204                                         SizeByte := SizeByte + Length( SaveList.Text );
1205                                         doc.Write(SaveList.Text);
1206                                         SaveList.Clear;
1207                                 end;
1208                                 SaveList.Add('<a name="bottom"></a>');
1209                                 SizeByte := SizeByte + Length( SaveList.Text );
1210                                 // \83X\83L\83\93(\83t\83b\83^)
1211                                 try
1212                                         SaveList.Add( LoadSkin( GetSkinFooterFileName ) );
1213                                 except
1214                                 end;
1215                                 doc.Write(SaveList.Text);
1216
1217                         end else if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
1218                                 //CSS\8eg\97p
1219                                 //CSSFileName := GetAppDir + CSS_FILE_NAME;
1220 //                              SaveList.Add('<html lang="ja"><head>');
1221                                 SaveList.Add('<html><head>');
1222                                 SaveList.Add('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1223                                 SaveList.Add('<title>' + sTitle + '</title>');
1224                                 SaveList.Add('<link rel="stylesheet" href="'+CSSFileName+'" type="text/css">');
1225                                 if Length( UserOptionalStyle ) > 0 then
1226                                         SaveList.Add('<style type="text/css">body {' + UserOptionalStyle + '}</style>');
1227                                 SaveList.Add('</head>');
1228                                 SaveList.Add('<body>');
1229                                 SaveList.Add('<a name="top"></a>');
1230                                 SaveList.Add('<div class="title">' + sTitle + '</div>');
1231                                 doc.Write(SaveList.Text);
1232                                 SaveList.Clear;
1233                                 //Application.ProcessMessages;
1234                                 for i := 0 to ReadList.Count - 1 do begin
1235                                         if (OnlyAHundredRes = true) and ( i <> 0 ) and ( (ReadList.Count-i) > 101 ) then begin
1236                                                 Continue;
1237                                         end;
1238                                         if (Trim(ReadList[i]) <> '') then begin
1239                                                 No := IntToStr(i + 1);
1240                                                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
1241                                                         SaveList.Add('<a name="new"></a><div class="new">\90V\92\85\83\8c\83X <span class="newdate">' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</span></div>');
1242                                                 end;
1243                                                 Res := DivideStrLine(ReadList[i]);
1244                                                 Res.FBody := ConvRes(Res.FBody, ThreadItem.ParentBoard.BBSID, ChangeFileExt(ThreadItem.FileName, ''), 'bbs', 'key', 'st', 'to', 'nofirst', 'true');
1245                                                 Res.FBody := AddAnchorTag(Res.FBody);
1246                                                 if Res.FName = '' then
1247                                                         Res.FName := '&nbsp;';
1248                                                 if Res.FMailTo = '' then
1249                                                         SaveList.Add('<a name="' + No + '"></a>'
1250                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span> '
1251                                                                                         + '<span class="name_label">\96¼\91O\81F</span> '
1252                                                                                         + '<span class="name"><b>' + Res.FName + '</b></span> '
1253                                                                                         + '<span class="date_label">\93\8a\8de\93ú\81F</span> '
1254                                                                                         + '<span class="date">' + Res.FDateTime+ '</span></div>'
1255                                                                                                                                                                                 + '<div class="mes">' + Res.FBody + ' </div>')
1256                                                 else if GikoSys.Setting.ShowMail then
1257                                                         SaveList.Add('<a name="' + No + '"></a>'
1258                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span>'
1259                                                                                                                                                                                 + '<span class="name_label"> \96¼\91O\81F </span>'
1260                                                                                         + '<a class="name_mail" href="mailto:' + Res.FMailTo + '">'
1261                                                                                         + '<b>' + Res.FName + '</b></a><span class="mail"> [' + Res.FMailTo + ']</span>'
1262                                                                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span>'
1263                                                                                         + '<span class="date"> ' + Res.FDateTime+ '</span></div>'
1264                                                                                         + '<div class="mes">' + Res.FBody + ' </div>')
1265                                                 else
1266                                                         SaveList.Add('<a name="' + No + '"></a>'
1267                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span>'
1268                                                                                         + '<span class="name_label"> \96¼\91O\81F </span>'
1269                                                                                         + '<a class="name_mail" href="mailto:' + Res.FMailTo + '">'
1270                                                                                         + '<b>' + Res.FName + '</b></a>'
1271                                                                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span>'
1272                                                                                         + '<span class="date"> ' + Res.FDateTime+ '</span></div>'
1273                                                                                                                                                                                 + '<div class="mes">' + Res.FBody + ' </div>');
1274                                                 if ThreadItem.Kokomade = (i + 1) then begin
1275                                                         SaveList.Add('<a name="koko"></a><div class="koko">\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</div>');
1276                                                 end;
1277                                         end;
1278
1279                                         doc.Write(SaveList.Text);
1280                                         SaveList.Clear;
1281                                 end;
1282                                 //FOnlyAHundredRes
1283                                 SaveList.Add('<a name="bottom"></a>');
1284                                 SaveList.Add('</body></html>');
1285                                 SaveList.Add('<a name="last"></a>');
1286                                 SaveList.Add('</body></html>');
1287
1288                                 doc.Write(SaveList.Text);
1289                         end else begin
1290                                 //CSS\94ñ\8eg\97p
1291 //                              SaveList.Add('<html lang="ja"><head>');
1292                                 SaveList.Add('<html><head>');
1293                                 SaveList.Add('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1294                                 SaveList.Add('<title>' + sTitle + '</title></head>');
1295                                 SaveList.Add('<body TEXT="#000000" BGCOLOR="#EFEFEF" link="#0000FF" alink="#FF0000" vlink="#660099">');
1296                                 SaveList.Add('<a name="top"></a>');
1297                                 SaveList.Add('<font size=+1 color="#FF0000">' + sTitle + '</font>');
1298                                 SaveList.Add('<dl>');
1299                                 doc.Write(SaveList.Text);
1300                                 SaveList.Clear;
1301                                 //Application.ProcessMessages;
1302                                 for i := 0 to ReadList.Count - 1 do begin
1303                                         if (OnlyAHundredRes = true) and ( i <> 0 ) and ( (ReadList.Count-i) > 101 ) then begin
1304                                                 Continue;
1305                                         end;
1306                                         if (Trim(ReadList[i]) <> '') then begin
1307                                                 No := IntToStr(i + 1);
1308
1309                                                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
1310                                                         SaveList.Add('</dl>');
1311                                                         SaveList.Add('<a name="new"></a>');
1312                                                         SaveList.Add('<table width="100%" bgcolor="#3333CC" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#6666FF" valign="middle"><font size="-1" color="#ffffff"><b>\90V\92\85\83\8c\83X ' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</b></font></td></tr></table>');
1313                                                         SaveList.Add('<dl>');
1314                                                 end;
1315                                                 Res := DivideStrLine(ReadList[i]);
1316                                                 Res.FBody := ConvRes(Res.FBody, ThreadItem.ParentBoard.BBSID, ChangeFileExt(ThreadItem.FileName, ''), 'bbs', 'key', 'st', 'to', 'nofirst', 'true');
1317                                                 if Res.FType = glt2chOld then begin
1318                                                         Res.FMailTo := StringReplace(Res.FMailTo, '\81\97\81M', ',', [rfReplaceAll]);
1319                                                         Res.FName := StringReplace(Res.FName, '\81\97\81M', ',', [rfReplaceAll]);
1320                                                         Res.FBody := StringReplace(Res.FBody, '\81\97\81M', ',', [rfReplaceAll]);
1321                                                 end;
1322                                                 Res.FBody := AddAnchorTag(Res.FBody);
1323                                                 if Res.FMailTo = '' then
1324                                                         SaveList.Add('<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<font color="forestgreen"><b> ' + Res.FName + ' </b></font> \93\8a\8de\93ú\81F ' + Res.FDateTime+ '<br><dd>' + Res.Fbody + ' <br><br><br>')
1325                                                 else if GikoSys.Setting.ShowMail then
1326                                                         SaveList.Add('<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<a href="mailto:' + Res.FMailTo + '"><b> ' + Res.FName + ' </B></a> [' + Res.FMailTo + '] \93\8a\8de\93ú\81F ' + Res.FDateTime+ '<br><dd>' + Res.Fbody + ' <br><br><br>')
1327                                                 else
1328                                                         SaveList.Add('<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<a href="mailto:' + Res.FMailTo + '"><b> ' + Res.FName + ' </B></a> \93\8a\8de\93ú\81F ' + Res.FDateTime+ '<br><dd>' + Res.Fbody + ' <br><br><br>');
1329                                                 if ThreadItem.Kokomade = (i + 1) then begin
1330                                                         SaveList.Add('</dl>');
1331                                                         SaveList.Add('<a name="koko"></a><table width="100%" bgcolor="#55AA55" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#77CC77" valign="middle"><font size="-1" color="#ffffff"><b>\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</b></font></td></tr></table>');
1332                                                         SaveList.Add('<dl>');
1333                                                 end;
1334                                         end;
1335                                         //if SaveList.Count > 50 then begin
1336                                                 doc.Write(SaveList.Text);
1337                                                 SaveList.Clear;
1338                                                 //Application.ProcessMessages;
1339                                         //end;
1340                                 end;
1341                                 SaveList.Add('</dl>');
1342                                 SaveList.Add('<a name="bottom"></a>');
1343                                 SaveList.Add('</body></html>');
1344                                 doc.Write(SaveList.Text);
1345                         end;
1346                 finally
1347                         SaveList.Free;
1348                         doc.Close;
1349                 end;
1350         finally
1351                 ReadList.Free;
1352         end;
1353 end;
1354 (*************************************************************************
1355  *http://\82Ì\95\8e\9a\97ñ\82ðanchor\83^\83O\95t\82«\82É\82·\82é\81B
1356  *************************************************************************)
1357 function TGikoSys.AddAnchorTag(s: string): string;
1358 const
1359         URL_CHAR: string = '0123456789'
1360                                                                          + 'abcdefghijklmnopqrstuvwxyz'
1361                                                                          + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
1362                                                                          + '#$%&()*+,-./:;=?@[]^_`{|}~!''\';
1363         ANCHOR_REF      = 'href=';
1364         RES_REF                 = '&gt;&gt;';
1365 var
1366         wkIdx: array[0..9] of Integer;
1367         url: string;
1368         href: string;
1369         i: Integer;
1370         idx: Integer;
1371         anchorLen : Integer;
1372 begin
1373         Result := '';
1374         // + 3 \82Í 'href="' ('"'\82Â\82«)\82È\82Ç\82Ì\83o\83\8a\83G\81[\83V\83\87\83\93\82É\97]\97T\82ð\8e\9d\82½\82¹\82é\82½\82ß
1375         anchorLen := Length( ANCHOR_REF ) + 3;
1376
1377         while True do begin
1378                 wkIdx[0] := AnsiPos('http://', s);
1379                 wkIdx[1] := AnsiPos('ttp://', s);
1380                 wkIdx[2] := AnsiPos('tp://', s);
1381                 wkIdx[3] := AnsiPos('ms-help://', s);
1382                 wkIdx[4] := AnsiPos('p://', s);
1383                 wkIdx[5] := AnsiPos('https://', s);
1384                 wkIdx[6] := AnsiPos('www.', s);
1385                 wkIdx[7] := AnsiPos('ftp://', s);
1386                 wkIdx[8] := AnsiPos('news://', s);
1387                 wkIdx[9] := AnsiPos('rtsp://', s);
1388
1389                 idx := MaxInt;
1390                 for i := 0 to 9 do
1391                         if wkIdx[i] <> 0 then idx := Min(wkIdx[i], idx);
1392
1393                 if idx = MaxInt then begin
1394                         //\83\8a\83\93\83N\82ª\96³\82¢\82æ\81B
1395                         Result := Result + s;
1396                         Break;
1397                 end;
1398
1399                 if (idx > 1) and
1400                         (Pos( ANCHOR_REF, Copy(s, idx - anchorLen, anchorLen ) ) > 0) then begin
1401                         //\8aù\82É\83\8a\83\93\83N\83^\83O\82ª\82Â\82¢\82Ä\82¢\82é\82Á\82Û\82¢\82Æ\82«\82Í\83\80\83V
1402                         href := Copy( s, idx, Length( s ) );
1403                         Result := Result + Copy( s, 1, idx + Pos( '</a>', href ) + Length( '</a>' ) - 2 );
1404                         s := href;
1405                         s := Copy( s, Pos( '</a>', s ) + Length( '</a>' ), Length( s ) );
1406
1407                         Continue;
1408                 end;
1409
1410                 Result := Result + Copy(s, 0, idx - 1);
1411
1412                 s := Copy(s, idx, length(s));
1413
1414                 for i := 0 to Length(s) do begin
1415                         idx := AnsiPos(s[i + 1], URL_CHAR);
1416                         if (idx = 0) or (i = (Length(s))) then begin
1417                                 //URL\82\82á\82È\82¢\95\8e\9a\94­\8c©\81I\82Æ\82©\81A\95\8e\9a\82ª\82È\82­\82È\82Á\82½\81B
1418                                 url := Copy(s, 0, i);
1419
1420                                 if AnsiPos('ttp://', url) = 1 then
1421                                         href := 'h' + url
1422                                 else if AnsiPos('tp://', url) = 1 then
1423                                         href := 'ht' + url
1424                                 else if AnsiPos('p://', url) = 1 then
1425                                         href := 'htt' + url
1426                                 else if AnsiPos('www.', url) = 1 then
1427                                         href := 'http://' + url
1428                                 else
1429                                         href := url;
1430                                 Result := Result + '<a href="' + href + '" target="_blank">' + url + '</a>';
1431                                 s := Copy(s, i + 1, Length(s));
1432                                 Break;
1433                         end;
1434                 end;
1435         end;
1436 end;
1437
1438 (*************************************************************************
1439  *\83T\83u\83W\83F\83N\83g\88ê\8ds\82ð\95ª\8a\84
1440  *************************************************************************)
1441 function TGikoSys.DivideSubject(Line: string): TSubjectRec;
1442 var
1443         i: integer;
1444         ws: WideString;
1445         Delim: string;
1446         LeftK: string;
1447         RightK: string;
1448 begin
1449         Result.FCount := 0;
1450
1451         if Pos('<>', Line) = 0 then
1452                 Delim := ','
1453         else
1454                 Delim := '<>';
1455
1456         Result.FFileName := GetTokenIndex(Line, Delim, 0);
1457         Result.FTitle := GetTokenIndex(Line, Delim, 1);
1458
1459         ws := Trim(Result.FTitle);
1460
1461         if Copy(ws, Length(ws), 1) = ')' then begin
1462                 LeftK := '(';
1463                 RightK := ')';
1464         end else if Copy(ws, Length(ws), 1) = '\81j' then begin
1465                 LeftK := '\81i';
1466                 RightK := '\81j';
1467         end else if Copy(ws, Length(ws), 1) = '<' then begin
1468                 LeftK := '<';
1469                 RightK := '>';
1470         end;
1471
1472         for i := Length(ws) - 1 downto 1 do begin
1473                 if ws[i] = LeftK then begin
1474                         ws := Copy(ws, i + 1, Length(ws) - i - 1);
1475                         if IsNumeric(ws) then
1476                                 Result.FCount := StrToInt(ws);
1477                         Result.FTitle := Trim(StringReplace(Result.FTitle, LeftK + ws + RightK, '', [rfReplaceAll]));
1478                         break;
1479                 end;
1480         end;
1481 end;
1482
1483 (*************************************************************************
1484  * dat\83t\83@\83C\83\8b\82Ì\88ê\83\89\83C\83\93\82ð\95ª\89ð
1485  *************************************************************************)
1486 function TGikoSys.DivideStrLine(Line: string): TResRec;
1487 var
1488         Delim: string;
1489                 bufbody : String;
1490 begin
1491         if Pos('<>', Line) = 0 then begin
1492                 Delim := ',';
1493                 Result.FType := glt2chOld;
1494         end else begin
1495                 Delim := '<>';
1496                 Result.FType := glt2chNew;
1497         end;
1498         Result.FName := Trim(GetTokenIndex(Line, Delim, 0));
1499         Result.FMailTo := Trim(GetTokenIndex(Line, Delim, 1));
1500         Result.FDateTime := Trim(GetTokenIndex(Line, Delim, 2));
1501         bufBody := Trim(GetTokenIndex(Line, Delim, 3));
1502         if bufbody = '' then begin
1503                 Insert('&nbsp;',bufbody, 1);
1504         end;
1505         Result.FBody := bufBody;
1506         Result.FTitle := Trim(GetTokenIndex(Line, Delim, 4));
1507
1508 end;
1509
1510 (*************************************************************************
1511  * URL\82©\82çBBSID\82ð\8eæ\93¾
1512  *************************************************************************)
1513 function TGikoSys.UrlToID(url: string): string;
1514 var
1515         i: integer;
1516 begin
1517         Result := '';
1518         url := Trim(url);
1519
1520         if url = '' then Exit;
1521
1522         url := Copy(url, 0, Length(url) - 1);
1523         for i := Length(url) downto 0 do begin
1524                 if url[i] = '/' then begin
1525                         Result := Copy(url, i + 1, Length(url));
1526                         Break;
1527                 end;
1528         end;
1529 end;
1530
1531 (*************************************************************************
1532  *URL\82©\82çBBSID\88È\8aO\82Ì\95\94\95ª(http://teri.2ch.net/)\82ð\8eæ\93¾
1533  *************************************************************************)
1534 function TGikoSys.UrlToServer(url: string): string;
1535 var
1536         i: integer;
1537         wsURL: WideString;
1538 begin
1539         Result := '';
1540         wsURL := url;
1541         wsURL := Trim(wsURL);
1542
1543         if wsURL = '' then exit;
1544
1545         if Copy(wsURL, Length(wsURL), 1) = '/' then
1546                 wsURL := Copy(wsURL, 0, Length(wsURL) - 1);
1547
1548         for i := Length(wsURL) downto 0 do begin
1549                 if wsURL[i] = '/' then begin
1550                         Result := Copy(wsURL, 0, i);
1551                         break;
1552                 end;
1553         end;
1554 end;
1555
1556 (*************************************************************************
1557  *\83f\83B\83\8c\83N\83g\83\8a\82ª\91\8dÝ\82·\82é\82©\83`\83F\83b\83N
1558  *************************************************************************)
1559 function TGikoSys.DirectoryExistsEx(const Name: string): Boolean;
1560 var
1561         Code: Integer;
1562 begin
1563         Code := GetFileAttributes(PChar(Name));
1564         Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
1565 end;
1566
1567 (*************************************************************************
1568  *\83f\83B\83\8c\83N\83g\83\8a\8dì\90¬\81i\95¡\90\94\8aK\91w\91Î\89\9e\81j
1569  *************************************************************************)
1570 function TGikoSys.ForceDirectoriesEx(Dir: string): Boolean;
1571 begin
1572         Result := True;
1573         if Length(Dir) = 0 then
1574                 raise Exception.Create('\83t\83H\83\8b\83_\82ª\8dì\90¬\8fo\97\88\82Ü\82¹\82ñ');
1575         Dir := ExcludeTrailingPathDelimiter(Dir);
1576         if (Length(Dir) < 3) or DirectoryExistsEx(Dir)
1577                 or (ExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
1578         Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
1579 end;
1580
1581 (*************************************************************************
1582  *\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
1583  *FDelphi\82©\82ç\82Ì\83p\83N\83\8a
1584  *************************************************************************)
1585 function TGikoSys.StrTokFirst(const s:string; const sep: TStrTokSeparator; var Rec: TStrTokRec): string;
1586 begin
1587         Rec.Str := s;
1588         Rec.Pos := 1;
1589         Result := StrTokNext(sep, Rec);
1590 end;
1591
1592 (*************************************************************************
1593  *\95\8e\9a\97ñ\82©\82ç\83g\81[\83N\83\93\82Ì\90Ø\82è\8fo\82µ
1594  *FDelphi\82©\82ç\82Ì\83p\83N\83\8a
1595  *************************************************************************)
1596 function TGikoSys.StrTokNext(const sep: TStrTokSeparator; var Rec: TStrTokRec): string;
1597 var
1598         Len, I: Integer;
1599 begin
1600         with Rec do     begin
1601                 Len := Length(Str);
1602                 Result := '';
1603                 if Len >= Pos then begin
1604                         while (Pos <= Len) and (Str[Pos] in sep) do begin
1605                          Inc(Pos);
1606                         end;
1607                         I := Pos;
1608                         while (Pos<= Len) and not (Str[Pos] in sep) do begin
1609                                 if IsDBCSLeadByte(Byte(Str[Pos])) then begin
1610                                         Inc(Pos);
1611                                 end;
1612                                 Inc(Pos);
1613                         end;
1614                         Result := Copy(Str, I, Pos - I);
1615                         while (Pos <= Len) and (Str[Pos] in sep) do begin// \82±\82ê\82Í\82¨\8dD\82Ý
1616                                 Inc(Pos);
1617                         end;
1618                 end;
1619         end;
1620 end;
1621
1622 (*************************************************************************
1623  *\83t\83@\83C\83\8b\83T\83C\83Y\8eæ\93¾
1624  *************************************************************************)
1625 function TGikoSys.GetFileSize(FileName : string): longint;
1626 var
1627         F : File;
1628 begin
1629         try
1630                 if not FileExists(FileName) then begin
1631                         Result := 0;
1632                         Exit;
1633                 end;
1634                 Assign(F, FileName);
1635                 Reset(F, 1);
1636                 Result := FileSize(F);
1637                 CloseFile(F);
1638         except
1639                 Result := 0;
1640         end;
1641 end;
1642
1643 (*************************************************************************
1644  *\83t\83@\83C\83\8b\8ds\90\94\8eæ\93¾
1645  *************************************************************************)
1646 function TGikoSys.GetFileLineCount(FileName : string): longint;
1647 var
1648         sl: TStringList;
1649 begin
1650         sl := TStringList.Create;
1651         try
1652                 try
1653                         sl.LoadFromFile(FileName);
1654                         Result := sl.Count;
1655                 except
1656                         Result := 0;
1657                 end;
1658         finally
1659                 sl.Free;
1660         end;
1661
1662 end;
1663
1664 (*************************************************************************
1665  *\83X\83\8c\83b\83h\83t\83@\83C\83\8b\82©\82ç\8ew\92è\8ds\82ð\8eæ\93¾
1666  *************************************************************************)
1667 function TGikoSys.ReadThreadFile(FileName: string; Line: Integer): string;
1668 var
1669         fileTmp : TStringList;
1670 begin
1671   Result := '';
1672   if FileExists(FileName) then begin
1673     fileTmp := TStringList.Create;
1674     try
1675       try
1676         fileTmp.LoadFromFile( FileName );
1677         if ( Line  >= 1 ) and ( Line  < fileTmp.Count + 1 ) then begin
1678                 Result := fileTmp.Strings[ Line-1 ];
1679         end;
1680       except
1681               //on EFOpenError do Result := '';
1682       end;
1683     finally
1684             fileTmp.Free;
1685     end;
1686   end;
1687 end;
1688
1689 (*************************************************************************
1690  *\83V\83X\83e\83\80\83\81\83j\83\85\81[\83t\83H\83\93\83g\82Ì\91®\90«\82ð\8eæ\93¾
1691  *************************************************************************)
1692 procedure TGikoSys.MenuFont(Font: TFont);
1693 var
1694         lf: LOGFONT;
1695         nm: NONCLIENTMETRICS;
1696 begin
1697         nm.cbSize := sizeof(NONCLIENTMETRICS);
1698
1699         SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @nm, 0);
1700         lf := nm.lfMenuFont;
1701
1702         Font.Name := lf.lfFaceName;
1703         Font.Height := lf.lfHeight;
1704         Font.Style := [];
1705         if lf.lfWeight >= 700 then
1706                 Font.Style := Font.Style + [fsBold];
1707         if lf.lfItalic = 1 then
1708                 Font.Style := Font.Style + [fsItalic];
1709 end;
1710
1711 (*************************************************************************
1712  *
1713  *\82Ç\82±\82©\82Ì\83T\83C\83g\82©\82ç\82Ì\83p\83N\83\8a
1714  *************************************************************************)
1715 function TGikoSys.RemoveToken(var s: string; delimiter: string): string;
1716 var
1717         p: Integer;
1718 begin
1719         p := AnsiPos(delimiter, s);
1720         if p = 0 then
1721                 Result := s
1722         else
1723                 Result := Copy(s, 1, p - 1);
1724         s := Copy(s, Length(Result) + Length(delimiter) + 1, Length(s));
1725 end;
1726
1727 (*************************************************************************
1728  *
1729  *\82Ç\82±\82©\82Ì\83T\83C\83g\82©\82ç\82Ì\83p\83N\83\8a
1730  *************************************************************************)
1731 function TGikoSys.GetTokenIndex(s: string; delimiter: string; index: Integer): string;
1732 var
1733         i: Integer;
1734 begin
1735         Result := '';
1736         for i := 0 to index do
1737                 Result := RemoveToken(s, delimiter);
1738 end;
1739
1740 (*************************************************************************
1741  *
1742  *************************************************************************)
1743 function TGikoSys.DeleteLink(const s: string): string;
1744 var
1745         s1: string;
1746         s2: string;
1747         idx: Integer;
1748         i: Integer;
1749 begin
1750         i := 0;
1751         Result := '';
1752         while True do begin
1753                 s1 := GetTokenIndex(s, '<a href="', i);
1754                 s2 := GetTokenIndex(s, '<a href="', i + 1);
1755
1756                 idx := Pos('">', s1);
1757                 if idx <> 0 then
1758                         Delete(s1, 1, idx + 1);
1759                 idx := Pos('">', s2);
1760                 if idx <> 0 then
1761                         Delete(s2, 1, idx + 1);
1762
1763                 Result := Result + s1 + s2;
1764
1765                 if s2 = '' then
1766                         Break;
1767
1768                 inc(i, 2);
1769         end;
1770 end;
1771
1772 //\83C\83\93\83f\83b\83N\83X\96¢\8dX\90V\83o\83b\83t\83@\82ð\83t\83\89\83b\83V\83\85\81I
1773 {procedure TGikoSys.FlashExitWrite;
1774 var
1775         i: Integer;
1776 begin
1777         //\83X\83\8c\83b\83h\83f\81[\83^\83t\83@\83C\83\8b\82ð\8dX\90V
1778         for i := 0 to FExitWrite.Count - 1 do
1779                 WriteThreadDat(FExitWrite[i]);
1780         FExitWrite.Clear;
1781 end;}
1782
1783 (*************************************************************************
1784  *\83X\83\8c\96¼\82È\82Ç\82ð\92Z\82¢\96¼\91O\82É\95Ï\8a·\82·\82é
1785  *from HotZonu
1786  *************************************************************************)
1787 function TGikoSys.GetShortName(const LongName: string; ALength: integer): string;
1788 const
1789         ERASECHAR : array [1..39] of string =
1790                 ('\81\99','\81\9a','\81¡','\81 ','\81\9f','\81\9e','\81Q','\81\94','\81£','\81¥',
1791                  '\81¢','\81¤','\81\9c','\81\9b','\81\9d','\81y','\81z','\81ô','\81s','\81t',
1792                  '\81g','\81h','\81k','\81l','\81e','\81f','\81\83','\81\84','\81á','\81â',
1793                  '\81o','\81p','\81q','\81r','\81w','\81x','\81¬','\81c', '\81@');
1794 var
1795         Chr : array [0..255]    of      char;
1796         S : string;
1797         i : integer;
1798 begin
1799         s := Trim(LongName);
1800         if (Length(s) <= ALength) then begin
1801                 Result := s;
1802         end else begin
1803                 S := s;
1804                 for i := Low(ERASECHAR) to      High(ERASECHAR) do      begin
1805                         S := StringReplace(S, ERASECHAR[i], '', [rfReplaceAll]);
1806                 end;
1807                 if (Length(S) <= ALength) then begin
1808                         Result := S;
1809                 end else begin
1810                         Windows.LCMapString(
1811                                         GetUserDefaultLCID(),
1812                                         LCMAP_HALFWIDTH,
1813                                         PChar(S),
1814                                         Length(S) + 1,
1815                                         chr,
1816                                         Sizeof(chr)
1817                                         );
1818                         S := Chr;
1819                         S := Copy(S,1,ALength);
1820                         while true do begin
1821                                 if (ByteType(S, Length(S)) = mbLeadByte ) then begin
1822                                         S := Copy(S, 1, Length(S) - 1);
1823                                 end else begin
1824                                         Break;
1825                                 end;
1826                         end;
1827                         Result := S;
1828                 end;
1829         end;
1830 end;
1831
1832 (*************************************************************************
1833  *
1834  * from HotZonu
1835  *************************************************************************)
1836 function TGikoSys.ConvRes(const Body, Bbs, Key,
1837         ParamBBS, ParamKey, ParamStart, ParamTo, ParamNoFirst, ParamTrue : string): string;
1838 type
1839         PIndex = ^TIndex;
1840         TIndex = record
1841                 FIndexFrom      : integer;
1842                 FIndexTo                : integer;
1843                 FNo                              : string;
1844         end;
1845 const
1846         GT      = '&gt;';
1847         SN      = '0123456789-';
1848         ZN      = '\82O\82P\82Q\82R\82S\82T\82U\82V\82W\82X\81|';
1849 var
1850         i : integer;
1851         s,r : string;
1852         b : TMbcsByteType;
1853         sw: boolean;
1854         sp: integer;
1855         No: string;
1856         sx: string;
1857         List: TList;
1858         oc      : string;
1859         st, et: string;
1860         chk : boolean;
1861         al : boolean;
1862         procedure Add(IndexFrom, IndexTo: integer; const No: string);
1863         var
1864                 FIndex : PIndex;
1865         begin
1866                 New(FIndex);
1867                 FIndex.FIndexFrom       := IndexFrom;
1868                 FIndex.FIndexTo         := IndexTo;
1869                 FIndex.FNo                               := No;
1870                 List.Add(FIndex);
1871         end;
1872         function ChooseString(const Text, Separator: string; Index: integer): string;
1873         var
1874                 S : string;
1875                 i, p : integer;
1876         begin
1877                 S :=    Text;
1878                 for i :=        0 to    Index - 1 do    begin
1879                         if      (AnsiPos(Separator, S) = 0) then        S :=    ''
1880                         else    S :=    Copy(S, AnsiPos(Separator, S) + Length(Separator), Length(S));
1881                 end;
1882                 p :=    AnsiPos(Separator, S);
1883                 if      (p > 0) then    Result  :=      Copy(S, 1, p - 1) else Result :=        S;
1884         end;
1885 begin
1886         { v1.0 b2 - 03 }
1887         s        :=     Body;
1888         r        :=     Body;
1889         i        :=     1;
1890         sw      :=      False;
1891         No      :=      '';
1892         List:=  TList.Create;
1893         oc      :=      '';
1894         sp      :=      0;
1895         chk :=  False;
1896         al      :=      False;
1897         while true      do      begin
1898                 b :=    ByteType(s, i);
1899                 case    b of
1900                         mbSingleByte    : begin
1901                                 if      (not sw) and (Copy(s,i,8) = GT + GT) then       begin
1902                                         if      (AnsiPos('<A HREF', AnsiUpperCase(oc)) = 0) then        begin
1903                                                 sw      :=      True;
1904                                                 sp      :=      i;
1905                                                 i :=    i + 7;
1906                                                 oc:='';
1907                                                 chk :=  True;
1908                                         end;
1909                                 end else
1910                                 if      (not sw) and (Copy(s,i,8) = GT + GT) then       begin
1911                                         if      (AnsiPos('<A HREF', AnsiUpperCase(oc)) = 1) then        begin
1912                                                 i :=    i + 7;
1913                                                 oc:='';
1914                                                 chk :=  True;
1915                                         end;
1916                                 end else
1917                                 if      (not sw) and (Copy(s,i,4) = GT) then    begin
1918                                         if      (AnsiPos('<A HREF', AnsiUpperCase(oc)) = 0) then        begin
1919                                                 sw      :=      True;
1920                                                 sp      :=      i;
1921                                                 i :=    i + 3;
1922                                                 oc:='';
1923                                                 chk :=  True;
1924                                         end;
1925                                 end else
1926                                 if      ((not sw) and (Copy(s,i,1) = ',')) or
1927                                                 ((not sw) and (Copy(s,i,1) = '=')) then begin
1928                                         if      ((not Chk) and (AnsiLowerCase(oc) = '</a>')) or
1929                                                         ((Chk) and      (oc = '')) or
1930                                                         ((not Chk) and (al)) then
1931                                         begin
1932                                                 sw      :=      True;
1933                                                 sp      :=      i;
1934                                                 //i :=  i + 1;
1935                                                 oc:='';
1936                                         end;
1937                                 end else
1938                                 if      (sw) then begin
1939                                         sx      :=      Copy(s,i,1);
1940                                         if      (AnsiPos(sx, SN) > 0)   then    begin
1941                                                 No      :=      No      + sx;
1942                                         end else begin
1943                                                 if      (No <> '') and (No <> '-')       then   begin
1944                                                         Add(sp, i, No);
1945                                                         al := True;
1946                                                 end;
1947                                                 sw      :=      False;
1948                                                 //
1949                                                 i := i - 1;
1950                                                 //
1951                                                 No      := '';
1952                                                 oc:='';
1953                                                 //chk :=        False;
1954                                         end;
1955                                 end else begin
1956                                         if      Copy(s,i,1) = '<' then  oc      :=      '';
1957                                         oc      :=      oc + Copy(s,i,1);
1958                                         chk :=  False;
1959                                         al      :=      False;
1960                                 end;
1961                         end;
1962                         mbLeadByte      : begin
1963                                 if      (not sw) and (Copy(s,i,4) = '\81\84\81\84') then        begin
1964                                         sw      :=      True;
1965                                         sp      :=      i;
1966                                         i :=    i + 3;
1967                                         chk :=  True;
1968                                 end else
1969                                 if      (not sw) and (Copy(s,i,2) = '\81\84') then  begin
1970                                         sw      :=      True;
1971                                         sp      :=      i;
1972                                         i :=    i + 1;
1973                                         chk :=  True;
1974                                 end else
1975                                 if      (sw) then begin
1976                                         sx      :=      Copy(s,i,2);
1977                                         if      (AnsiPos(sx, ZN) > 0)   then    begin
1978                                                 No      :=      No      + ZenToHan(sx);
1979                                         end else begin
1980                                                 if      (No <> '') and (No <> '-')      and (No <> '\81|') then   begin
1981                                                         Add(sp, i, No);
1982                                                 end;
1983                                                 sw      :=      False;
1984                                                 i := i - 1;
1985                                                 No      :=      '';
1986                                         end;
1987                                 end else begin
1988                                         oc      :=      '';
1989                                         chk :=  False;
1990                                 end;
1991                                 al      :=      False;
1992                         end;
1993                 end;
1994                 inc(i);
1995                 if      (i > Length(Body))      then    begin
1996                         if      (sw)    then    begin
1997                                 if      (No <> '')      then    Add(sp, i, No);
1998                         end;
1999                         Break;
2000                 end;
2001         end;
2002         for i :=        List.Count - 1  downto  0 do    begin
2003                 if      (AnsiPos('-', PIndex(List[i]).FNo) > 0) then    begin
2004                         st      :=      ChooseString(PIndex(List[i]).FNo, '-', 0);
2005                         et      :=      ChooseString(PIndex(List[i]).FNo, '-', 1);
2006                 end else begin
2007                         st      :=      PIndex(List[i]).FNo;
2008                         et      :=      PIndex(List[i]).FNo;
2009                 end;
2010                 r :=    Copy(r,0, PIndex(List[i]).FIndexFrom - 1) +
2011                                         Format('<a href="../test/read.cgi?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s" target="_blank">',
2012                                                                 [ParamBBS, Bbs, ParamKey, Key, ParamStart, st, ParamTo, et, ParamNoFirst, ParamTrue]) +
2013                                         Copy(r,PIndex(List[i]).FIndexFrom, PIndex(List[i]).FIndexTo - PIndex(List[i]).FIndexFrom) + '</A>' +
2014                                         Copy(r,PIndex(List[i]).FIndexTo,Length(r));
2015                 Dispose(PIndex(List[i]));
2016         end;
2017         List.Free;
2018         Result  :=      r;
2019 end;
2020
2021 (*************************************************************************
2022  * \91S\8ap\81¨\94¼\8ap
2023  * from HotZonu
2024  *************************************************************************)
2025 function TGikoSys.ZenToHan(const s: string): string;
2026 var
2027         Chr: array [0..255] of char;
2028 begin
2029         Windows.LCMapString(
2030                  GetUserDefaultLCID(),
2031 //               LCMAP_HALFWIDTH,
2032                  LCMAP_HALFWIDTH or LCMAP_KATAKANA or LCMAP_LOWERCASE,
2033                  PChar(s),
2034                  Length(s) + 1,
2035                  chr,
2036                  Sizeof(chr)
2037                  );
2038         Result := Chr;
2039 end;
2040
2041 (*************************************************************************
2042  * \91S\8ap\94¼\8ap\82Ð\82ç\82ª\82È\82©\82½\82©\82È\82ð\8bæ\95Ê\82µ\82È\82¢\90¦\82¢Pos
2043  *************************************************************************)
2044 function TGikoSys.VaguePos(const Substr, S: string): Integer;
2045 begin
2046         Result := Pos(ZenToHan(Substr), ZenToHan(S));
2047 end;
2048
2049 function TGikoSys.BoolToInt(b: Boolean): Integer;
2050 begin
2051         Result := IfThen(b, 1, 0);
2052 end;
2053
2054 function TGikoSys.IntToBool(i: Integer): Boolean;
2055 begin
2056         Result := i = 1;
2057 end;
2058
2059 //gzip\82Å\88³\8fk\82³\82ê\82½\82Ì\82ð\96ß\82·
2060 function TGikoSys.GzipDecompress(ResStream: TStream; ContentEncoding: string): string;
2061 const
2062         BUF_SIZE = 4096;
2063 var
2064         GZipStream: TGzipDecompressStream;
2065         TextStream: TStringStream;
2066         buf: array[0..BUF_SIZE - 1] of Byte;
2067         cnt: Integer;
2068         s: string;
2069         i: Integer;
2070 begin
2071         Result := '';
2072         TextStream := TStringStream.Create('');
2073         try
2074 //\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¢)
2075 //              if LowerCase(Trim(ContentEncoding)) = 'gzip' then begin
2076                 if AnsiPos('gzip', LowerCase(Trim(ContentEncoding))) > 0 then begin
2077                         ResStream.Position := 0;
2078                         GZipStream := TGzipDecompressStream.Create(TextStream);
2079                         try
2080                                 repeat
2081                                         FillChar(buf, BUF_SIZE, 0);
2082                                         cnt := ResStream.Read(buf, BUF_SIZE);
2083                                         if cnt > 0 then
2084                                                 GZipStream.Write(buf, BUF_SIZE);
2085                                 until cnt = 0;
2086                         finally
2087                                 GZipStream.Free;
2088                         end;
2089                 end else begin
2090                         ResStream.Position := 0;
2091                         repeat
2092                                 FillChar(buf, BUF_SIZE, 0);
2093                                 cnt := ResStream.Read(buf, BUF_SIZE);
2094                                 if cnt > 0 then
2095                                         TextStream.Write(buf, BUF_SIZE);
2096                         until cnt = 0;
2097                 end;
2098
2099                 //NULL\95\8e\9a\82ð"*"\82É\82·\82é
2100                 s := TextStream.DataString;
2101                 i := Length(s);
2102                 while (i > 0) and (s[i] = #0) do
2103                         Dec(i);
2104                 s := Copy(s, 1, i);
2105
2106                 i := Pos(#0, s);
2107                 while i <> 0 do begin
2108                         s[i] := '*';
2109                         i := Pos(#0, s);
2110                 end;
2111                 Result := s;
2112         finally
2113                 TextStream.Free;
2114         end;
2115 end;
2116
2117 procedure TGikoSys.LoadKeySetting(ActionList: TActionList);
2118 const
2119         STD_SEC = 'KeySetting';
2120 var
2121         i: Integer;
2122         ini: TMemIniFile;
2123         ActionName: string;
2124         ActionKey: Integer;
2125         SecList: TStringList;
2126         Component: TComponent;
2127 begin
2128         if not FileExists(GetConfigDir + KEY_SETTING_FILE_NAME) then
2129                 Exit;
2130         SecList := TStringList.Create;
2131         ini := TMemIniFile.Create(GetConfigDir + KEY_SETTING_FILE_NAME);
2132         try
2133                 ini.ReadSection(STD_SEC, SecList);
2134                 for i := 0 to SecList.Count - 1 do begin
2135                         ActionName := SecList[i];
2136                         ActionKey := ini.ReadInteger(STD_SEC, ActionName, -1);
2137                         if ActionKey <> -1 then begin
2138                                 Component := ActionList.Owner.FindComponent(ActionName);
2139                                 if TObject(Component) is TAction then begin
2140                                         TAction(Component).ShortCut := ActionKey;
2141                                 end;
2142                         end;
2143                 end;
2144         finally
2145                 ini.Free;
2146                 SecList.Free;
2147         end;
2148 end;
2149
2150 procedure TGikoSys.SaveKeySetting(ActionList: TActionList);
2151 const
2152         STD_SEC = 'KeySetting';
2153 var
2154         i: Integer;
2155         ini: TMemIniFile;
2156 begin
2157         ini := TMemIniFile.Create(GetConfigDir + KEY_SETTING_FILE_NAME);
2158         try
2159                 for i := 0 to ActionList.ActionCount - 1 do begin
2160                         if ActionList.Actions[i].Tag = -1 then
2161                                 Continue;
2162                         ini.WriteInteger(STD_SEC, ActionList.Actions[i].Name, TAction(ActionList.Actions[i]).ShortCut);
2163                 end;
2164                 ini.UpdateFile;
2165         finally
2166                 ini.Free;
2167         end;
2168 end;
2169
2170 //
2171 procedure TGikoSys.CreateProcess(const AppPath: string; const Param: string);
2172 var
2173         PI: TProcessInformation;
2174         SI: TStartupInfo;
2175         Path: string;
2176 begin
2177         Path := '"' + AppPath + '"';
2178         if Param <> '' then
2179                 Path := Path + ' ' + Param;
2180
2181         SI.Cb := SizeOf(Si);
2182         SI.lpReserved   := nil;
2183         SI.lpDesktop     := nil;
2184         SI.lpTitle               := nil;
2185         SI.dwFlags               := 0;
2186         SI.cbReserved2 := 0;
2187         SI.lpReserved2 := nil;
2188         SI.dwysize               := 0;
2189         Windows.CreateProcess(nil,
2190                                                                 PChar(Path),
2191                                                                 nil,
2192                                                                 nil,
2193                                                                 False,
2194                                                                 0,
2195                                                                 nil,
2196                                                                 nil,
2197                                                                 SI,
2198                                                                 PI);
2199 end;
2200
2201 procedure TGikoSys.OpenBrowser(URL: string; BrowserType: TGikoBrowserType);
2202 begin
2203         case BrowserType of
2204                 gbtIE:
2205                         HlinkNavigateString(nil, PWideChar(WideString(URL)));
2206                 gbtUserApp, gbtAuto:
2207                         if (Setting.URLApp) and (FileExists(Setting.URLAppFile)) then
2208                                 GikoSys.CreateProcess(Setting.URLAppFile, URL)
2209                         else
2210                                 HlinkNavigateString(nil, PWideChar(WideString(URL)));
2211         end;
2212 end;
2213
2214 function TGikoSys.HTMLDecode(const AStr: String): String;
2215 var
2216         Sp, Rp, Cp, Tp: PChar;
2217         S: String;
2218         I, Code: Integer;
2219         Num: Boolean;
2220 begin
2221         SetLength(Result, Length(AStr));
2222         Sp := PChar(AStr);
2223         Rp := PChar(Result);
2224         //Cp := Sp;
2225         try
2226                 while Sp^ <> #0 do begin
2227                         case Sp^ of
2228                                 '&': begin
2229                                                          //Cp := Sp;
2230                                                          Inc(Sp);
2231                                                          case Sp^ of
2232                                                                  'a': if AnsiStrPos(Sp, 'amp;') = Sp then
2233                                                                                         begin
2234                                                                                                 Inc(Sp, 3);
2235                                                                                                 Rp^ := '&';
2236                                                                                         end;
2237                                                                  'l',
2238                                                                  'g': if (AnsiStrPos(Sp, 'lt;') = Sp) or (AnsiStrPos(Sp, 'gt;') = Sp) then
2239                                                                                         begin
2240                                                                                                 Cp := Sp;
2241                                                                                                 Inc(Sp, 2);
2242                                                                                                 while (Sp^ <> ';') and (Sp^ <> #0) do
2243                                                                                                         Inc(Sp);
2244                                                                                                 if Cp^ = 'l' then
2245                                                                                                         Rp^ := '<'
2246                                                                                                 else
2247                                                                                                         Rp^ := '>';
2248                                                                                         end;
2249                                                                  'q': if AnsiStrPos(Sp, 'quot;') = Sp then
2250                                                                                         begin
2251                                                                                                 Inc(Sp,4);
2252                                                                                                 Rp^ := '"';
2253                                                                                         end;
2254                                                                  '#': begin
2255                                                                                                 Tp := Sp;
2256                                                                                                 Inc(Tp);
2257                                                                                                 Num := IsNumeric(Copy(Tp, 1, 1));
2258                                                                                                 while (Sp^ <> ';') and (Sp^ <> #0) do begin
2259                                                                                                         if (Num) and (not IsNumeric(Copy(Sp, 1, 1))) then
2260                                                                                                                 Break;
2261                                                                                                         Inc(Sp);
2262                                                                                                 end;
2263                                                                                                 SetString(S, Tp, Sp - Tp);
2264                                                                                                 Val(S, I, Code);
2265                                                                                                 Rp^ := Chr((I));
2266                                                                                         end;
2267                                                          //      else
2268                                                                          //raise EConvertError.CreateFmt(sInvalidHTMLEncodedChar,
2269                                                                                  //[Cp^ + Sp^, Cp - PChar(AStr)])
2270                                                          end;
2271                                          end
2272                         else
2273                                 Rp^ := Sp^;
2274                         end;
2275                         Inc(Rp);
2276                         Inc(Sp);
2277                 end;
2278         except
2279 //              on E:EConvertError do
2280 //                      raise EConvertError.CreateFmt(sInvalidHTMLEncodedChar,
2281 //                              [Cp^ + Sp^, Cp - PChar(AStr)])
2282         end;
2283         SetLength(Result, Rp - PChar(Result));
2284 end;
2285
2286 function TGikoSys.GetHRefText(s: string): string;
2287 var
2288         Index: Integer;
2289         Index2: Integer;
2290 begin
2291         Result := '';
2292         s := Trim(s);
2293         if s = '' then
2294                 Exit;
2295
2296         Index := AnsiPos('href', LowerCase(s));
2297         if Index = 0 then
2298                 Exit;
2299         s := Trim(Copy(s, Index + 4, Length(s)));
2300         s := Trim(Copy(s, 2, Length(s)));
2301
2302         //\8en\82ß\82Ì\95\8e\9a\82ª'"'\82È\82ç\8eæ\82è\8f\9c\82­
2303         if Copy(s, 1, 1) = '"' then begin
2304                 s := Trim(Copy(s, 2, Length(s)));
2305         end;
2306
2307         Index := AnsiPos('"', s);
2308         if Index <> 0 then begin
2309                 //'"'\82Ü\82ÅURL\82Æ\82·\82é
2310                 s := Copy(s, 1, Index - 1);
2311         end else begin
2312                 //'"'\82ª\96³\82¯\82ê\82Î\83X\83y\81[\83X\82©">"\82Ì\91\81\82¢\95û\82Ü\82Å\82ðURL\82Æ\82·\82é
2313                 Index := AnsiPos(' ', s);
2314                 Index2 := AnsiPos('>', s);
2315                 if Index = 0 then
2316                         Index := Index2;
2317                 if Index > Index2 then
2318                         Index := Index2;
2319                 if Index <> 0 then
2320                         s := Copy(s, 1, Index - 1)
2321                 else
2322                         //\82±\82ê\88È\8fã\82à\82¤\92m\82ç\82ñ\82Ê
2323                         ;
2324         end;
2325         Result := Trim(s);
2326 end;
2327
2328 //\83z\83X\83g\96¼\82ª\82Q\82\83\82\88\82©\82Ç\82¤\82©\83`\83F\83b\83N\82·\82é
2329 function TGikoSys.Is2chHost(Host: string): Boolean;
2330 const
2331         HOST_NAME: array[0..1] of string = ('2ch.net', 'bbspink.com');
2332 var
2333         i: Integer;
2334 //      Len: Integer;
2335 begin
2336         Result := False;
2337         OutputDebugString(pchar(HOST_NAME[0]));
2338         for i := 0 to Length(HOST_NAME) - 1 do begin
2339 //              Len := Length(HOST_NAME[i]);
2340                 if AnsiPos(HOST_NAME[i], Host) = (Length(Host) - Length(HOST_NAME[i]) + 1) then begin
2341                         Result := True;
2342                         Exit;
2343                 end;
2344         end;
2345 end;
2346
2347 function TGikoSys.Parse2chURL(const url: string; const path: string; const document: string; var BBSID: string; var BBSKey: string): Boolean;
2348 const
2349         READ_PATH: string =                     '/test/read.cgi/';
2350         OLD_READ_PATH: string =         '/test/read.cgi?';
2351         KAKO_PATH: string =                     '/kako/';
2352 var
2353         Index: Integer;
2354         s: string;
2355         SList: TStringList;
2356 begin
2357         BBSID := '';
2358         BBSKey := '';
2359         Result := False;
2360
2361         Index := AnsiPos(READ_PATH, path);
2362         if Index <> 0 then begin
2363                 s := Copy(path, Length(READ_PATH) + 1, Length(path));
2364                 BBSID := GetTokenIndex(s, '/', 0);
2365                 BBSKey := GetTokenIndex(s, '/', 1);
2366                 if BBSKey = '' then
2367                         BBSKey := Document;
2368                 Result := (BBSID <> '') or (BBSKey <> '');
2369                 Exit;
2370         end;
2371         Index := AnsiPos(KAKO_PATH, path);
2372         if Index <> 0 then begin
2373                 s := Copy(path, 2, Length(path));
2374                 BBSID := GetTokenIndex(s, '/', 0);
2375                 if (BBSID = 'log') and (GetTokenIndex(s, '/', 2) = 'kako') then
2376                         BBSID := GetTokenIndex(s, '/', 1);
2377                 BBSKey := ChangeFileExt(Document, '');
2378                 Result := (BBSID <> '') or (BBSKey <> '');
2379                 Exit;
2380         end;
2381         Index := AnsiPos('read.cgi?', URL);
2382         if Index <> 0 then begin
2383                 SList := TStringList.Create;
2384                 try
2385                         try
2386 //                              s := HTMLDecode(Document);
2387                                 ExtractHTTPFields(['?', '&'], [], PChar(URL), SList, False);
2388                                 BBSID := SList.Values['bbs'];
2389                                 BBSKey := SList.Values['key'];
2390                                 Result := (BBSID <> '') or (BBSKey <> '');
2391                                 Exit;
2392                         except
2393                                 Exit;
2394                         end;
2395                 finally
2396                         SList.Free;
2397                 end;
2398         end;
2399 end;
2400
2401 function TGikoSys.Parse2chURL2(URL: string): TPathRec;
2402 var
2403         i: Integer;
2404         s: string;
2405         wk: string;
2406         wkMin: Integer;
2407         wkMax: Integer;
2408         wkInt: Integer;
2409         RStart: Integer;
2410         RLength: Integer;
2411         SList: TStringList;
2412 begin
2413         URL := Trim(LowerCase(URL));
2414         Result.FBBS := '';
2415         Result.FKey := '';
2416         Result.FSt := 0;
2417         Result.FTo := 0;
2418         Result.FFirst := False;
2419         Result.FStBegin := False;
2420         Result.FToEnd := False;
2421         Result.FDone := False;
2422
2423         wkMin := 0;
2424         wkMax := 1;
2425
2426         FAWKStr.RegExp := 'http://.+\.(2ch\.net|bbspink\.com)/';
2427         if FAWKStr.Match(FAWKStr.ProcessEscSeq(URL), RStart, RLength) = 0 then
2428                 Exit;
2429         s := Copy(URL, RStart + RLength - 1, Length(URL));
2430
2431         //\95W\8f\80\8f\91\8e®
2432         //\8dÅ\8cã\82Íl50, 10, 10-20, 10n, 10-20n, -10, 10-, 10n- \82È\82Ç
2433         //http://xxx.2ch.net/test/read.cgi/bbsid/1000000000/
2434         FAWKStr.RegExp := '/test/read.cgi/.+/[0-9]+/.*';
2435         if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2436                 s := Copy(s, 15, Length(s));
2437
2438                 SList := TStringList.Create;
2439                 try
2440                         SList.Clear;
2441                         FAWKStr.RegExp := '/';
2442                         if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 2 then begin
2443                                 Result.FBBS := SList[1];
2444                                 Result.FKey := SList[2];
2445                                 if SList.Count >= 3 then
2446                                         s := SList[3]
2447                                 else
2448                                         s := '';
2449                         end else
2450                                 Exit;
2451
2452                         SList.Clear;
2453                         FAWKStr.LineSeparator := mcls_CRLF;
2454                         FAWKStr.RegExp := '-';
2455                         if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) = 0 then begin
2456                                 Result.FFirst := True;
2457                         end else begin
2458                                 FAWKStr.RegExp := 'l[0-9]+';
2459                                 if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2460                                         Result.FFirst := True;
2461                                 end else begin
2462                                         for i := 0 to SList.Count - 1 do begin
2463                                                 if Trim(SList[i]) = '' then begin
2464                                                         if i = 0 then
2465                                                                 Result.FStBegin := True;
2466                                                         if i = (SList.Count - 1) then
2467                                                                 Result.FToEnd := True;
2468                                                 end else if IsNumeric(SList[i]) then begin
2469                                                         wkInt := StrToInt(SList[i]);
2470                                                         wkMax := Max(wkMax, wkInt);
2471                                                         if wkMin = 0 then
2472                                                                 wkMin := wkInt
2473                                                         else
2474                                                                 wkMin := Min(wkMin, wkInt);
2475                                                 end else if Trim(SList[i]) = 'n' then begin
2476                                                         Result.FFirst := True;
2477                                                 end else begin
2478                                                         FAWKStr.RegExp := '^n[0-9]+$|^[0-9]+n$';
2479                                                         if FAWKStr.Match(FAWKStr.ProcessEscSeq(SList[i]), RStart, RLength) > 0 then begin
2480                                                                 if Copy(SList[i], 1, 1) = 'n' then
2481                                                                         wkInt := StrToInt(Copy(SList[i], 2, Length(SList[i])))
2482                                                                 else
2483                                                                         wkInt := StrToInt(Copy(SList[i], 1, Length(SList[i]) - 1));
2484                                                                 Result.FFirst := True;
2485                                                                 wkMax := Max(wkMax, wkInt);
2486                                                                 if wkMin = 1 then
2487                                                                         wkMin := wkInt
2488                                                                 else
2489                                                                         wkMin := Min(wkMin, wkInt);
2490                                                         end;
2491                                                 end;
2492                                         end;
2493                                         if Result.FStBegin and (not Result.FToEnd) then
2494                                                 Result.FSt := wkMin
2495                                         else if (not Result.FStBegin) and Result.FToEnd then
2496                                                 Result.FTo := wkMax
2497                                         else if (not Result.FStBegin) and (not Result.FToEnd) then begin
2498                                                 Result.FSt := wkMin;
2499                                                 Result.FTo := wkMax;
2500                                         end;
2501                                         //Result.FSt := wkMin;
2502                                         //Result.FTo := wkMax;
2503                                 end;
2504                         end;
2505                 finally
2506                         SList.Free;
2507                 end;
2508                 Result.FDone := True;
2509                 Exit;
2510         end;
2511
2512         //\90Vkako\8f\91\8e®
2513         //http://server.2ch.net/ITA_NAME/kako/1000/10000/1000000000.html
2514         FAWKStr.RegExp := '/.+/kako/[0-9]+/[0-9]+/[0-9]+\.html';
2515         if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2516                 SList := TStringList.Create;
2517                 try
2518                         SList.Clear;
2519                         FAWKStr.RegExp := '/';
2520                         if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 6 then begin
2521                                 Result.FBBS := SList[1];
2522                                 Result.FKey := ChangeFileExt(SList[5], '');
2523                                 Result.FFirst := True;
2524                         end else
2525                                 Exit;
2526                 finally
2527                         SList.Free;
2528                 end;
2529                 Result.FDone := True;
2530                 Exit;
2531         end;
2532
2533         //\8b\8ckako\8f\91\8e®
2534         //http://server.2ch.net/ITA_NAME/kako/999/999999999.html
2535         FAWKStr.RegExp := '/.+/kako/[0-9]+/[0-9]+\.html';
2536         if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2537                 SList := TStringList.Create;
2538                 try
2539                         SList.Clear;
2540                         FAWKStr.RegExp := '/';
2541                         if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 5 then begin
2542                                 Result.FBBS := SList[1];
2543                                 Result.FKey := ChangeFileExt(SList[4], '');
2544                                 Result.FFirst := True;
2545                         end else
2546                                 Exit;
2547                 finally
2548                         SList.Free;
2549                 end;
2550                 Result.FDone := True;
2551                 Exit;
2552         end;
2553
2554         //log\8by\82Ñlog2\8f\91\8e®
2555         //http://server.2ch.net/log/ITA_NAME/kako/999/999999999.html
2556         //http://server.2ch.net/log2/ITA_NAME/kako/999/999999999.html
2557         FAWKStr.RegExp := '/log2?/.+/kako/[0-9]+/[0-9]+\.html';
2558         if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2559                 SList := TStringList.Create;
2560                 try
2561                         SList.Clear;
2562                         FAWKStr.RegExp := '/';
2563                         if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 6 then begin
2564                                 Result.FBBS := SList[2];
2565                                 Result.FKey := ChangeFileExt(SList[5], '');
2566                                 Result.FFirst := True;
2567                         end else
2568                                 Exit;
2569                 finally
2570                         SList.Free;
2571                 end;
2572                 Result.FDone := True;
2573                 Exit;
2574         end;
2575
2576
2577         //\8b\8cURL\8f\91\8e®
2578         //http://server.2ch.net/test/read.cgi?bbs=ITA_NAME&key=1000000000&st=1&to=5&nofirst=true
2579         FAWKStr.RegExp := '/test/read\.cgi\?';
2580         if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
2581                 s := Copy(s, 16, Length(s));
2582                 SList := TStringList.Create;
2583                 try
2584                         SList.Clear;
2585                         FAWKStr.RegExp := '&';
2586                         if FAWKStr.Split(FAWKStr.ProcessEscSeq(s), SList) >= 2 then begin
2587                                 Result.FFirst := True;
2588                                 for i := 0 to SList.Count - 1 do begin
2589                                         if Pos('bbs=', SList[i]) = 1 then begin
2590                                                 Result.FBBS := Copy(SList[i], 5, Length(SList[i]));
2591                                         end else if Pos('key=', SList[i]) = 1 then begin
2592                                                 Result.FKey := Copy(SList[i], 5, Length(SList[i]));
2593                                         end else if Pos('st=', SList[i]) = 1 then begin
2594                                                 wk := Copy(SList[i], 4, Length(SList[i]));
2595                                                 if IsNumeric(wk) then
2596                                                         Result.FSt := StrToInt(wk)
2597                                                 else if wk = '' then
2598                                                         Result.FStBegin := True;
2599                                         end else if Pos('to=', SList[i]) = 1 then begin
2600                                                 wk := Copy(SList[i], 4, Length(SList[i]));
2601                                                 if IsNumeric(wk) then
2602                                                         Result.FTo := StrToInt(wk)
2603                                                 else if wk = '' then
2604                                                         Result.FToEnd := True;
2605                                         end else if Pos('nofirst=', SList[i]) = 1 then begin
2606                                                 Result.FFirst := False;
2607                                         end;
2608                                 end;
2609                         end else
2610                                 Exit;
2611                 finally
2612                         SList.Free;
2613                 end;
2614
2615                 if (Result.FBBS <> '') and (Result.FKey <> '') then begin
2616                         Result.FDone := True;
2617                 end;
2618                 Exit;
2619         end;
2620 end;
2621
2622 procedure TGikoSys.ParseURI(var URL, Protocol, Host, Path, Document, Port, Bookmark: string);
2623 var
2624         URI: TIdURI;
2625 begin
2626         Protocol := '';
2627         Host := '';
2628         Path := '';
2629         Document := '';
2630         Port := '';
2631         Bookmark := '';
2632         URI := TIdURI.Create(URL);
2633         try
2634                 Protocol := URI.Protocol;
2635                 Host := URI.Host;
2636                 Path := URI.Path;
2637                 Document := URI.Document;
2638                 Port := URI.Port;
2639                 Bookmark := URI.Bookmark;
2640         finally
2641                 URI.Free;
2642         end;
2643 end;
2644
2645 function TGikoSys.GetVersionBuild: Integer;
2646 var
2647         FixedFileInfo: PVSFixedFileInfo;
2648         VersionHandle, VersionSize: DWORD;
2649         pVersionInfo: Pointer;
2650         ItemLen : UInt;
2651         AppFile: string;
2652 begin
2653         Result := 0;
2654         AppFile := Application.ExeName;
2655         VersionSize := GetFileVersionInfoSize(pChar(AppFile), VersionHandle);
2656         if VersionSize = 0 then
2657                 Exit;
2658         GetMem(pVersionInfo, VersionSize);
2659         try
2660                 if GetFileVersionInfo(PChar(AppFile),VersionHandle,VersionSize, pVersionInfo) then
2661                         if VerQueryValue(pVersionInfo, '\', Pointer(FixedFileInfo), ItemLen) then
2662                                 Result := LOWORD(FixedFileInfo^.dwFileVersionLS);
2663         finally
2664                 FreeMem(pVersionInfo, VersionSize);
2665         end;
2666 end;
2667
2668 initialization
2669         GikoSys := TGikoSys.Create;
2670
2671 finalization
2672         if GikoSys <> nil then begin
2673                 GikoSys.Free;
2674                 GikoSys := nil;
2675         end;
2676 end.