OSDN Git Service

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