OSDN Git Service

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