OSDN Git Service

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