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