OSDN Git Service

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