OSDN Git Service

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