OSDN Git Service

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