OSDN Git Service

1.52.1.658
[gikonavigoeson/gikonavi.git] / HTMLCreate.pas
1 unit HTMLCreate;
2
3 interface
4
5 uses
6         Windows, Messages, SysUtils, Classes, {Graphics,} Controls, {Forms,}
7         ComCtrls, IniFiles, ShellAPI, Math, GikoSystem,
8 {$IF Defined(DELPRO) }
9         SHDocVw,
10         MSHTML,
11 {$ELSE}
12         SHDocVw_TLB,
13         MSHTML_TLB,
14 {$IFEND}
15         {HttpApp,} YofUtils, {URLMon,} BoardGroup, {gzip,} {Dolib,}
16         {bmRegExp,} AbonUnit,   MojuUtils, Setting,
17         ExternalBoardManager, ExternalBoardPlugInMain{,}
18         {Sort,} ,GikoBayesian, HintWindow, ActiveX;
19
20 type
21
22         PResLinkRec = ^TResLinkRec;
23         TResLinkRec = record
24                 FBbs: string;
25                 FKey : string;
26         end;
27
28         TBufferedWebBrowser = class(TStringList)
29         private
30                 //! \8f\91\82«\8d\9e\82Þ\83u\83\89\83E\83U
31                 FBrowser: TWebBrowser;
32                 //! \89½\8ds\82Ü\82Å\82½\82ß\82é\82©\82Ì\83T\83C\83Y
33                 FBuffSize: Integer;
34                 //! \83u\83\89\83E\83U\82ÌIHTMLDocument2\83C\83\93\83^\83t\83F\81[\83X\82ð\95Û\8e\9d\82·\82é open\82©\82çclose\82Ì\8aÔ\82Å
35                 FBrowserDoc: Variant;
36         public
37                 constructor Create(Browser: TWebBrowser; BuffSize: Integer);
38                 destructor Destory;
39                 procedure Open;
40                 procedure Close;
41                 procedure Flush;
42                 function Add(const S: string): Integer; override;
43         end;
44         THTMLCreate = class(TObject)
45         private
46                 { Private \90é\8c¾ }
47                 anchorLen                       : Integer;
48                 pURLCHARs,pURLCHARe : PChar;
49                 pANCHORs, pANCHORe  : PChar;
50                 pCTAGLs,  pCTAGLe   : PChar;
51                 pCTAGUs,  pCTAGUe   : PChar;
52                 pREF_MARKSs : array[0..9] of PChar;
53                 pREF_MARKSe : array[0..9] of PChar;
54                 constructor Create;
55
56                 function AddBeProfileLink(AID : string; ANum: Integer):string ;
57                 procedure CreateUsePluginHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
58                 procedure CreateUseSKINHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList);
59                 procedure CreateUseCSSHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
60                 procedure CreateDefaultHTML (html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
61                 procedure ConvertResAnchor(PRes: PResRec);
62                 procedure separateNumber(var st: String; var et: String; const Text, Separator: String);
63                 function checkComma(const s : String; var j : Integer; var No  : String) : boolean;
64                 function addResAnchor(PAddRes: PResRec; PResLink : PResLinkRec; dat : boolean;
65                  var s : String; j : Integer; const No: String) : string;
66         public
67                 { Public \90é\8c¾ }
68                 procedure AddAnchorTag(PRes: PResRec);
69                 function LoadFromSkin(fileName: string; ThreadItem: TThreadItem; SizeByte: Integer): string;
70                 function SkinedRes(const skin: string; PRes: PResRec; const No: string): string;
71                 procedure ConvRes( PRes : PResRec; PResLink : PResLinkRec; DatToHTML: boolean = false); overload;
72                 function ConvRes(const Body, Bbs, Key,  ParamBBS, ParamKey, ParamStart, ParamTo, ParamNoFirst, ParamTrue : string; DatToHTML: boolean = false): string; overload;
73                 procedure CreateHTML2(Browser: TWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
74                 procedure CreateHTML3(var html: TStringList; ThreadItem: TThreadItem; var sTitle: string);
75                 //\83\8c\83X\83|\83b\83v\83A\83b\83v\82Ì\8dì\90¬
76                 procedure SetResPopupText(Hint :TResPopup; threadItem: TThreadItem; StNum, ToNum: Integer; Title, First: Boolean);
77                 //\83\8a\83\93\83N\82Ì\95\8e\9a\97ñ\82©\82ç\83\8c\83X\83|\83b\83v\83A\83b\83v\97p\82ÌURL\82É\95Ï\8a·\82·\82é
78                 class function GetRespopupURL(AText, AThreadURL : string): string;
79                 //\8ew\92è\82µ\82½\83p\83X\82É\83X\83L\83\93\82à\82µ\82­\82ÍCSS\82Ì\83t\83@\83C\83\8b\82Ì\83R\83s\81[\82ð\8dì\82é
80                 class procedure SkinorCSSFilesCopy(path: string);
81                 //dat\82P\8ds\82ð\83\8c\83X\82É\95ª\89ð\82·\82é
82                 class procedure DivideStrLine(Line: string; PRes: PResRec);
83         //HTML\82©\82ç\83\8a\83\93\83N\83^\83O\82ð\8dí\8f\9c\82·\82é
84                 class function DeleteLink(const s: string): string;
85         end;
86
87 var
88         HTMLCreater: THTMLCreate;
89
90 implementation
91
92 const
93         URL_CHAR: string = '0123456789'
94                                                                          + 'abcdefghijklmnopqrstuvwxyz'
95                                                                          + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
96                                                                          + '#$%&()*+,-./:;=?@[]^_`{|}~!''\';
97         ANCHOR_REF      = 'href=';
98         CLOSE_TAGAL = '</a>';
99         CLOSE_TAGAU = '</A>';
100         RES_REF                 = '&gt;&gt;';
101         REF_MARK: array[0..9] of string = ('http://', 'ttp://', 'tp://',
102                                                                          'ms-help://','p://', 'https://',
103                                                                          'www.', 'ftp://','news://','rtsp://');
104
105 constructor THTMLCreate.Create;
106 var
107         j : Integer;
108 begin
109         // + 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ß
110         anchorLen := Length( ANCHOR_REF ) + 3;
111         pANCHORs  := PChar(ANCHOR_REF);
112         pANCHORe  := pANCHORs + Length(ANCHOR_REF);
113         pURLCHARs := PChar(URL_CHAR);
114         pURLCHARe := pURLCHARs + Length(URL_CHAR);
115         pCTAGLs   := PChar(CLOSE_TAGAL);
116         pCTAGLe   := pCTAGLs + 4;
117         pCTAGUs   := PChar(CLOSE_TAGAU);
118         pCTAGUe   := pCTAGUs + 4;
119         for j := 0 to 9 do begin
120                 pREF_MARKSs[j] := PChar(REF_MARK[j]);
121                 pREF_MARKSe[j] := pREF_MARKSs[j] + Length(REF_MARK[j]);
122         end;
123 end;
124 // \83X\83L\83\93\82ð\93Ç\82Ý\8d\9e\82Ý\81A\92l\82ð\92u\8a·\82·\82é
125 function THTMLCreate.LoadFromSkin(
126         fileName: string;
127         ThreadItem: TThreadItem;
128         SizeByte: Integer
129 ): string;
130 var
131         Skin: TStringList;
132 begin
133
134         Skin := TStringList.Create;
135         try
136                 if FileExists( fileName ) then begin
137                         Skin.LoadFromFile( fileName );
138
139                         // \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
140                         try
141                                 if ThreadItem.ParentBoard <> nil then
142                                         if ThreadItem.ParentBoard.ParentCategory <> nil then
143                                                 CustomStringReplace( Skin, '<BBSNAME/>', ThreadItem.ParentBoard.ParentCategory.ParenTBBS.Title);
144                                         CustomStringReplace( Skin, '<THREADURL/>', ThreadItem.URL);
145                         except end;
146                         CustomStringReplace( Skin, '<BOARDNAME/>', ThreadItem.ParentBoard.Title);
147                         CustomStringReplace( Skin, '<BOARDURL/>', ThreadItem.ParentBoard.URL);
148                         CustomStringReplace( Skin, '<THREADNAME/>', ThreadItem.Title);
149                         CustomStringReplace( Skin, '<SKINPATH/>', GikoSys.Setting.CSSFileName);
150                         CustomStringReplace( Skin, '<GETRESCOUNT/>', IntToStr( ThreadItem.Count - ThreadItem.NewResCount ));
151                         CustomStringReplace( Skin, '<NEWRESCOUNT/>', IntToStr( ThreadItem.NewResCount ));
152                         CustomStringReplace( Skin, '<ALLRESCOUNT/>', IntToStr( ThreadItem.Count ));
153
154                         CustomStringReplace( Skin, '<NEWDATE/>',FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate));
155                         CustomStringReplace( Skin, '<SIZEKB/>', IntToStr( Floor( SizeByte / 1024 ) ));
156                         CustomStringReplace( Skin, '<SIZE/>', IntToStr( SizeByte ));
157
158                         //----- \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µ
159                         // \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
160                         if GikoSys.Setting.UseKatjushaType then begin
161                                 try
162                                         if ThreadItem.ParentBoard <> nil then
163                                                 if ThreadItem.ParentBoard.ParentCategory <> nil then
164                                                         CustomStringReplace( Skin, '&BBSNAME', ThreadItem.ParentBoard.ParentCategory.ParenTBBS.Title);
165                                                 CustomStringReplace( Skin, '&THREADURL', ThreadItem.URL);
166                                 except end;
167                                 CustomStringReplace( Skin, '&BOARDNAME', ThreadItem.ParentBoard.Title);
168                                 CustomStringReplace( Skin, '&BOARDURL', ThreadItem.ParentBoard.URL);
169                                 CustomStringReplace( Skin, '&THREADNAME', ThreadItem.Title);
170                                 CustomStringReplace( Skin, '&SKINPATH', GikoSys.Setting.CSSFileName);
171                                 CustomStringReplace( Skin, '&GETRESCOUNT', IntToStr( ThreadItem.NewReceive - 1 ));
172                                 CustomStringReplace( Skin, '&NEWRESCOUNT', IntToStr( ThreadItem.NewResCount ));
173                                 CustomStringReplace( Skin, '&ALLRESCOUNT', IntToStr( ThreadItem.AllResCount ));
174
175                                 CustomStringReplace( Skin, '&NEWDATE', FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate));
176                                 CustomStringReplace( Skin, '&SIZEKB', IntToStr( Floor( SizeByte / 1024 ) ));
177                                 CustomStringReplace( Skin, '&SIZE', IntToStr( SizeByte ));
178                         end
179                         //----- \82±\82±\82Ü\82Å
180                 end;
181                 Result := Skin.Text;
182         finally
183                 Skin.Free;
184         end;
185 end;
186
187 // \83\8c\83X\82Ì\92l\82ð\92u\8a·\82·\82é
188 function THTMLCreate.SkinedRes(
189         const skin: string;
190         PRes: PResRec;
191         const No: string
192 ): string;
193 const
194         FORMT_NAME = '<b>%s</b>';
195         FORMT_NUM  = '<a href="menu:%s" name="%s">%s</a>';
196         FORMT_MAILNAME  = '<a href="mailto:%s"><b>%s</b></a>';
197 var
198         spamminess      : Extended;
199 {$IFDEF SPAM_FILTER_ENABLED}
200         wordCount               : TWordCount;
201 {$ENDIF}
202 begin
203 {$IFDEF SPAM_FILTER_ENABLED}
204         wordCount := TWordCount.Create;
205         try
206                 spamminess := Floor( GikoSys.SpamParse(
207                         Res.FName + '<>' + Res.FMailTo + '<>' + Res.FBody, wordCount ) * 100 );
208 {$ELSE}
209         spamminess := 0;
210 {$ENDIF}
211                 Result := CustomStringReplace( skin, '<SPAMMINESS/>', FloatToStr( spamminess ) );
212                 Result := CustomStringReplace( Result, '<NONSPAMMINESS/>', FloatToStr( 100 - spamminess ) );
213                 Result := CustomStringReplace( Result, '<MAIL/>', PRes.FMailTo);
214                 Result := CustomStringReplace( Result, '<DATE/>', PRes.FDateTime);
215                 Result := CustomStringReplace( Result, '<PLAINNUMBER/>', No);
216                 Result := CustomStringReplace( Result, '<NAME/>',
217                         Format(FORMT_NAME, [PRes.FName]));
218                 Result := CustomStringReplace( Result, '<NUMBER/>',
219                         Format(FORMT_NUM, [No, No, No]));
220                 Result := CustomStringReplace( Result, '<MAILNAME/>',
221                         Format(FORMT_MAILNAME,[PRes.FMailTo, PRes.FName]));
222                 Result := CustomStringReplace( Result, '<MESSAGE/>', PRes.FBody);
223
224                 //----- \82©\82¿\82ã\81`\82µ\82á\8cÝ\8a·\97p\81B\83R\83\81\83\93\83g\83A\83E\83g\82µ\82Ä\82à\82æ\82µ
225                 if GikoSys.Setting.UseKatjushaType then begin
226                         Result := CustomStringReplace( Result, '&NUMBER',
227                                 '<a href="menu:' + No + '" name="' + No + '">' + No + '</a>');
228                         Result := CustomStringReplace( Result, '&PLAINNUMBER', No);
229                         Result := CustomStringReplace( Result, '&NAME', '<b>' + PRes.FName + '</b>');
230                         Result := CustomStringReplace( Result, '&MAILNAME',
231                                 '<a href="mailto:' + PRes.FMailTo + '"><b>' + PRes.FName + '</b></a>');
232                         Result := CustomStringReplace( Result, '&MAIL', PRes.FMailTo);
233                         Result := CustomStringReplace( Result, '&DATE', PRes.FDateTime);
234                         Result := CustomStringReplace( Result, '&MESSAGE', PRes.FBody);
235                         Result := CustomStringReplace( Result, '&SPAMMINESS', FloatToStr( spamminess ) );
236                         Result := CustomStringReplace( Result, '&NONSPAMMINESS', FloatToStr( 100 - spamminess ) );
237                 end;
238                 //----- \82±\82±\82Ü\82Å
239 {$IFDEF SPAM_FILTER_ENABLED}
240         finally
241                 wordCount.Free;
242         end;
243 {$ENDIF}
244
245 end;
246 (*************************************************************************
247  *http://\82Ì\95\8e\9a\97ñ\82ðanchor\83^\83O\95t\82«\82É\82·\82é\81B
248  *************************************************************************)
249 procedure THTMLCreate.AddAnchorTag(PRes: PResRec);
250 const
251         _HEAD : array[0..9] of String =
252                 ('', 'h', 'ht', '', 'htt', '', 'http://', '', '', '');
253 var
254         url: string;
255         href: string;
256         i, j, b: Integer;
257         tmp: Integer;
258         idx, idx2: Integer;
259         pos : PChar;
260         pp, pe : PChar;
261         s : String;
262         len : Integer;
263 begin
264         s := PRes.FBody;
265         PRes.FBody := '';
266
267         //while True do begin
268         repeat
269                 idx  := MaxInt;
270                 idx2 := MaxInt;
271                 pp := PChar(s);
272                 pe := pp + Length(s);
273
274                 for j := 0 to 9 do begin
275                         pos := AnsiStrPosEx(pp, pe, pREF_MARKSs[j], pREF_MARKSe[j]);
276                         if pos <> nil then begin
277                                 tmp := pos - pp + 1;
278                                 idx := Min(tmp, idx);
279                                 if idx = tmp then idx2 := j;   //\82Ç\82Ì\83}\81[\83N\82Å\88ø\82Á\82©\82©\82Á\82½\82©\82ð\95Û\91
280                         end;
281                 end;
282
283                 if idx = MaxInt then begin
284                         //\83\8a\83\93\83N\82ª\96³\82¢\82æ\81B
285                         len := Length(PRes.FBody);
286                         SetLength(PRes.FBody, Length(s) + len);
287                         Move(pp^, PRes.FBody[len + 1], Length(s));
288                 end else begin
289                         if (idx > anchorLen) and
290                                 (AnsiStrPosEx(pp + idx - 1 - anchorLen, pp + idx, pANCHORs, pANCHORe) <> nil) then begin
291                                 //\8aù\82É\83\8a\83\93\83N\83^\83O\82ª\82Â\82¢\82Ä\82¢\82é\82Á\82Û\82¢\82Æ\82«\82Í\83\80\83V
292                                 //</a></A>\82ð\92T\82·\81A\8f¬\95\8e\9a\82Å\8c©\82Â\82©\82ç\82È\82¯\82ê\82Î\91å\95\8e\9a\82Å\8c\9f\8dõ
293                                 pos := AnsiStrPosEx(pp + idx, pe, pCTAGLs, pCTAGLe);
294                                 if pos = nil then
295                                         pos := AnsiStrPosEx(pp + idx, pe, pCTAGUs, pCTAGUe);
296                                 if pos = nil then
297                                         b := Length(REF_MARK[idx2])
298                                 else
299                                         b := pos - (pp  + idx) + 1;
300
301                                 len := Length(PRes.FBody);
302                                 SetLength(PRes.FBody, len + idx + b );
303                                 Move(pp^, PRes.FBody[len + 1], idx + b);
304                                 Delete(s, 1, idx + b);
305                         end else begin
306                                 pp      := PChar(s);
307                                 len     := Length(PRes.FBody);
308                                 SetLength(PRes.FBody, len + idx - 1);
309                                 Move(pp^, PRes.FBody[len + 1], idx - 1);
310
311                                 Delete(s, 1, idx - 1);
312                                 b := Length( s ) + 1;
313                                 pp      := PChar(s);
314                                 for i := 1 to b do begin
315                                         //\82P\83o\83C\83g\95\8e\9a\82ÅURL\82É\8eg\82¦\82È\82¢\95\8e\9a\82È\82ç
316                                         if (AnsiStrPosEx(pURLCHARs, pURLCHARe, pp, pp + 1) = nil) then begin
317                                                 url := Copy(s, 1, i - 1);
318                                                 Delete(s, 1, i - 1);
319                                                 href := Format('%s%s', [_HEAD[idx2], url]);
320                                                 PRes.FBody
321                                                         := Format('%s<a href="%s" target="_blank">%s</a>', [PRes.FBody, href, url]);
322                                                 Break;
323                                         end;
324                                         //\88ê\95\8e\9a\90i\82ß\82é\81B
325                                         Inc(pp);
326                                 end;
327                         end;
328                 end;
329         until idx = MaxInt;
330 end;
331
332 //\88ø\90\94\81AAID\81F\91Î\8fÛ\82Æ\82È\82é\93ú\95tID\95\8e\9a\97ñ\81AANum:\83\8c\83X\94Ô AURL\81F\82»\82Ì\83X\83\8c\83b\83h\82ÌURL
333 function THTMLCreate.AddBeProfileLink(AID : string; ANum: Integer):string ;
334 const
335         BE_MARK : string = 'BE:';
336 var
337         p : integer;
338         BNum, BMark : string;
339 begin
340         p := AnsiPos(BE_MARK, AnsiUpperCase(AID));
341         if p > 0 then begin
342                 BNum := Copy(AID, p, Length(AID));
343                 AID := Copy(AID, 1, p - 1);
344                 p := AnsiPos('-', BNum);
345                 if p > 0 then begin
346                         BMark := '?' + Trim(Copy(BNum, p + 1, Length(BNum)));
347                         BNum := Copy(BNum, 1, p - 1);
348                 end;
349                 BNum := Trim(BNum);
350                 Result := AID + ' <a href="'  + BNum + '/' + IntToStr(ANum)
351                         + '" target=_blank>' + BMark + '</a>';
352         end else
353                 Result := AID;
354 end;
355 procedure THTMLCreate.separateNumber(var st: String; var et: String; const Text:String; const Separator: String);
356 var
357         p : Integer;
358 begin
359         p := Pos(Separator,Text);
360         if (p > 0 ) then begin
361                 st := Copy(Text, 1, p - 1);
362                 et := Copy(Text, p + Length(Separator), Length(Text));
363         end else begin
364                 st := Text;
365                 et := Text;
366         end;
367 end;
368 procedure THTMLCreate.ConvRes( PRes : PResRec; PResLink : PResLinkRec; DatToHTML: boolean = false);
369 const
370         GT      = '&gt;';
371         SN      = '0123456789';
372         //\8c\9f\8dõ\91Î\8fÛ\82Ì\95\8e\9a\97ñ\8cS
373         TOKEN : array[0..5] of string = (GT+GT, GT, '\81\84\81\84', '\81\84', '<a ', '<A ');
374 var
375         i : integer;
376         s : string;
377         sw: boolean;
378         cm: boolean;
379         No: string;
380         oc      : string;
381         pos, pmin : integer;
382         j : integer;
383         ch : string;
384         db : boolean;
385         len : integer;
386         rink : string;
387
388         procedure getNumberString;
389         begin
390                 while (j <= len) do begin
391                         if (ByteType(s, j) = mbSingleByte) then begin
392                                 //1byte\95\8e\9a
393                                 ch := s[j];
394                                 Inc(j);
395                                 db := false;
396                         end else begin
397                                 //2byte\95\8e\9a
398                                 ch := ZenToHan(Copy(s, j, 2));
399                                 Inc(j, 2);
400                                 db := true;
401                         end;
402
403                         if System.Pos(ch, SN) > 0 then begin
404                                 No := No + ch;
405                         end else if (ch = '-') then begin
406                                 if sw then break;
407                                 if No = '' then break;
408                                 No := No + ch;
409                                 sw := true;
410                         end else begin
411                                 break;
412                         end;
413                 end;
414         end;
415
416 begin
417         //s \82É\96{\95\82ð\91S\95\94\93ü\82ê\82é
418         s        :=     PRes.FBody;
419         //\8c\8b\89Ê\82ð\83N\83\8a\83A
420         PRes.FBody       :=     '';
421
422         //
423         while Length(s) > 2 do begin
424                 pmin := Length(s) + 1;
425                 i       := Length(token);
426                 for j := 0 to 5 do begin
427                         pos := AnsiPos(TOKEN[j], s);
428                         if pos <> 0 then begin
429                                 if pos < pmin then begin
430                                         //\82Ç\82ê\82Å\83q\83b\83g\82µ\82½\82©\95Û\91
431                                         i := j;
432                                         //\8dÅ\8f¬\92l\82ð\8dX\90V
433                                         pmin := pos;
434                                 end;
435                         end;
436                 end;
437
438                 //\83q\83b\83g\82µ\82½\95\8e\9a\97ñ\82Ì\88ê\82Â\8eè\91O\82Ü\82Å\8c\8b\89Ê\82É\83R\83s\81[
439                 PRes.FBody := PRes.FBody + Copy(s, 1, pmin - 1);
440                 Delete(s, 1, pmin - 1);
441
442                 if i = 6 then begin
443                         //\83q\83b\83g\82È\82µ
444                 end else if (i = 4) or (i = 5) then begin
445                         //'<a ' or '<A' \82Å\83q\83b\83g '</a>' or '</A>' \82Ü\82Å\83R\83s\81[
446                         pmin := AnsiPos('</a>' , s);
447                         pos := AnsiPos('</A>' , s);
448                         if (pmin <> 0) and (pos <> 0) then begin
449                                 if (pmin > pos) then begin
450                                         pmin := pos;
451                                 end;
452                         end else if (pos <> 0) then begin
453                                 pmin := pos;
454                         end;
455                         rink := Copy(s, 1, pmin + 3);
456                         PRes.FBody := PRes.FBody + rink;
457                         Delete(s, 1, pmin + 3);
458
459                         pmin := Length(rink);
460                         i       := Length(TOKEN);
461                         for j := 0 to 3 do begin
462                                 pos := AnsiPos(TOKEN[j], rink);
463                                 if pos <> 0 then begin
464                                         if pos < pmin then begin
465                                                 //\82Ç\82ê\82Å\83q\83b\83g\82µ\82½\82©\95Û\91
466                                                 i := j;
467                                                 //\8dÅ\8f¬\92l\82ð\8dX\90V
468                                                 pmin := pos;
469                                         end;
470                                 end;
471                         end;
472                         // \83\8c\83X\83A\83\93\83J\81[\82ª\8aÜ\82Ü\82ê\82Ä\82¢\82½\82ç,\82ª\91±\82­\8cÀ\82è\83A\83\93\83J\81[\82Æ\82µ\82Ä\88µ\82¤
473                         if i <= 3 then begin
474                                 No := '';
475                                 j := 1;
476                                 len := Length(s);
477                                 cm := checkComma(s, j, No);
478                                 len := Length(s);
479                                 while cm do begin
480                                         oc := '';
481                                         No := '';
482                                         sw := false;
483                                         db := false;
484                                         getNumberString;
485                                         //\8fI\92[\82Ü\82Å\8ds\82Á\82Ä\82Ì\8fI\97¹\82©\83`\83F\83b\83N
486                                         if j <= len then begin
487                                                 if db then j := j - 2
488                                                 else j := j - 1;
489                                         end;
490                                         addResAnchor(PRes, PResLink, DatToHTML, s, j, No);
491                                         j := 1;
492                                         len := Length(s);
493                                         cm := checkComma(s, j, No);
494                                 end;
495                         end;
496                 end else begin
497                         //\89½\82©\82µ\82ç\8c©\82Â\82©\82Á\82½\83p\83^\81[\83\93
498                         j := Length(TOKEN[i]) + 1;
499                         oc := '';
500                         No := '';
501                         sw := false;
502                         db := false;
503                         len := Length(s);
504                         getNumberString;
505                         //\8fI\92[\82Ü\82Å\8ds\82Á\82Ä\82Ì\8fI\97¹\82©\83`\83F\83b\83N
506                         if j <= len then begin
507                                 if db then j := j - 2
508                                 else j := j - 1;
509                         end;
510                         addResAnchor(PRes, PResLink, DatToHTML, s, j, No);
511                 end;
512         end;
513         if Length(s) > 0 then begin
514                 PRes.FBody := PRes.FBody + s;
515         end;
516 end;
517 function THTMLCreate.checkComma(
518         const s : String;
519         var j : Integer;
520         var No  : String
521 ) : boolean;
522 var
523         bType : TMbcsByteType;
524 begin
525         Result := false;
526         if (Length(s) > 0) then begin
527                 bType := ByteType(s, j);
528                 if ((bType = mbSingleByte) and (s[j] = ',') or
529                         ((bType = mbLeadByte) and (ZenToHan(Copy(s, j ,2)) = ','))) then begin
530                         Result := true;
531                         if (bType = mbSingleByte) then
532                                 Inc(j)
533                         else
534                                 Inc(j, 2);
535                         No := '';
536                 end;
537         end;
538 end;
539 function THTMLCreate.addResAnchor(
540         PAddRes: PResRec; PResLink : PResLinkRec; dat : boolean;
541         var s : String; j : Integer; const No: String) : string;
542 const
543         FORMAT_LINK = '<a href="../test/read.cgi?bbs=%s&key=%s&st=%s&to=%s&nofirst=true" target="_blank">';
544 var
545         st,et : string;
546 begin
547
548         //\89½\82à\90\94\8e\9a\82ª\8c©\82Â\82©\82ç\82È\82¢\82Æ\82«
549         if No = '' then begin
550                 PAddRes.FBody := PAddRes.FBody + Copy(s, 1, j - 1);
551         end else begin
552                 separateNumber(st, et, No, '-');
553
554                 if not dat then begin
555                         PAddRes.FBody := PAddRes.FBody +
556                                 Format(FORMAT_LINK, [PResLink.FBbs, PResLink.FKey, st, et]);
557                 end else begin
558                         PAddRes.FBody := PAddRes.FBody + Format('<a href="#%s">', [st]);
559                 end;
560                 PAddRes.FBody := PAddRes.FBody + Copy(s, 1, j - 1) + '</a>';
561         end;
562         Delete(s, 1, j - 1);
563 end;
564
565 (*************************************************************************
566  *
567  * from HotZonu
568  *************************************************************************)
569 function THTMLCreate.ConvRes(const Body, Bbs, Key,
570         ParamBBS, ParamKey, ParamStart, ParamTo, ParamNoFirst, ParamTrue : string;
571         DatToHTML: boolean = false): string;
572 const
573         GT      = '&gt;';
574         SN      = '0123456789';
575         FORMAT_LINK = '<a href="../test/read.cgi?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s" target="_blank">';
576         //\8c\9f\8dõ\91Î\8fÛ\82Ì\95\8e\9a\97ñ\8cS
577         TOKEN : array[0..5] of string = (GT+GT, GT, '\81\84\81\84', '\81\84', '<a ', '<A ');
578 var
579         i : integer;
580         s : string;
581         sw: boolean;
582         cm: boolean;
583         No: string;
584         oc      : string;
585         pos, pmin : integer;
586         j : integer;
587         ch : string;
588         db : boolean;
589         len : integer;
590         rink : string;
591         function addResAnchor(const Left :string) : string;
592         var
593                 st,et : string;
594         begin
595                 //\8fI\92[\82Ü\82Å\8ds\82Á\82Ä\82Ì\8fI\97¹\82©\83`\83F\83b\83N
596                 if j <= len then begin
597                         if db then j := j - 2
598                         else j := j - 1;
599                 end;
600                 //\89½\82à\90\94\8e\9a\82ª\8c©\82Â\82©\82ç\82È\82¢\82Æ\82«
601                 if No = '' then begin
602                         Result := Left + Copy(s, 1, j - 1);
603                 end else begin
604                         separateNumber(st, et, No, '-');
605
606                         if not DatToHTML then begin
607                                 Result := Left + Format(FORMAT_LINK,
608                                                         [ParamBBS, Bbs, ParamKey, Key, ParamStart, st, ParamTo, et, ParamNoFirst, ParamTrue]);
609                         end else begin
610                                 Result := Left + Format('<a href="#%s">', [st]);
611                         end;
612                         Result := Result + Copy(s, 1, j - 1) + '</a>';
613                 end;
614                 Delete(s, 1, j - 1);
615         end;
616
617         procedure getNumberString;
618         begin
619                 while (j <= len) do begin
620                         if (ByteType(s, j) = mbSingleByte) then begin
621                                 //1byte\95\8e\9a
622                                 ch := s[j];
623                                 Inc(j);
624                                 db := false;
625                         end else begin
626                                 //2byte\95\8e\9a
627                                 ch := ZenToHan(Copy(s, j, 2));
628                                 Inc(j, 2);
629                                 db := true;
630                         end;
631
632                         if System.Pos(ch, SN) > 0 then begin
633                                 No := No + ch;
634                         end else if (ch = '-') then begin
635                                 if sw then break;
636                                 if No = '' then break;
637                                 No := No + ch;
638                                 sw := true;
639                         end else begin
640                                 break;
641                         end;
642                 end;
643         end;
644
645         function checkComma : boolean;
646         begin
647                 j := 1;
648                 len := Length(s);
649                 if ((len > 0) and (s[j] = ',')) or ((len > 1) and (ZenToHan(Copy(s, j ,2)) = ','))  then begin
650                         Result := true;
651                         if (ByteType(s, j) = mbSingleByte) then
652                                 Inc(j)
653                         else
654                                 Inc(j, 2);
655                         No := '';
656                 end else begin
657                         Result := false;
658                 end;
659         end;
660 begin
661         //s \82É\96{\95\82ð\91S\95\94\93ü\82ê\82é
662         s        :=     Body;
663         //\8c\8b\89Ê\82ð\83N\83\8a\83A
664         Result   :=     '';
665
666         //
667         while Length(s) > 2 do begin
668                 pmin := Length(s) + 1;
669                 i       := Length(token);
670                 for j := 0 to 5 do begin
671                         pos := AnsiPos(TOKEN[j], s);
672                         if pos <> 0 then begin
673                                 if pos < pmin then begin
674                                         //\82Ç\82ê\82Å\83q\83b\83g\82µ\82½\82©\95Û\91
675                                         i := j;
676                                         //\8dÅ\8f¬\92l\82ð\8dX\90V
677                                         pmin := pos;
678                                 end;
679                         end;
680                 end;
681
682                 //\83q\83b\83g\82µ\82½\95\8e\9a\97ñ\82Ì\88ê\82Â\8eè\91O\82Ü\82Å\8c\8b\89Ê\82É\83R\83s\81[
683                 Result := Result + Copy(s, 1, pmin - 1);
684                 Delete(s, 1, pmin - 1);
685
686                 if i = 6 then begin
687                         //\83q\83b\83g\82È\82µ
688                 end else if (i = 4) or (i = 5) then begin
689                         //'<a ' or '<A' \82Å\83q\83b\83g '</a>' or '</A>' \82Ü\82Å\83R\83s\81[
690                         pmin := AnsiPos('</a>' , s);
691                         pos := AnsiPos('</A>' , s);
692                         if (pmin <> 0) and (pos <> 0) then begin
693                                 if (pmin > pos) then begin
694                                         pmin := pos;
695                                 end;
696                         end else if (pos <> 0) then begin
697                                 pmin := pos;
698                         end;
699                         rink := Copy(s, 1, pmin + 3);
700                         Result := Result + rink;
701                         Delete(s, 1, pmin + 3);
702
703                         pmin := Length(rink);
704                         i       := Length(TOKEN);
705                         for j := 0 to 3 do begin
706                                 pos := AnsiPos(TOKEN[j], rink);
707                                 if pos <> 0 then begin
708                                         if pos < pmin then begin
709                                                 //\82Ç\82ê\82Å\83q\83b\83g\82µ\82½\82©\95Û\91
710                                                 i := j;
711                                                 //\8dÅ\8f¬\92l\82ð\8dX\90V
712                                                 pmin := pos;
713                                         end;
714                                 end;
715                         end;
716                         // \83\8c\83X\83A\83\93\83J\81[\82ª\8aÜ\82Ü\82ê\82Ä\82¢\82½\82ç,\82ª\91±\82­\8cÀ\82è\83A\83\93\83J\81[\82Æ\82µ\82Ä\88µ\82¤
717                         if i <= 3 then begin
718                                 No := '';
719                                 cm := checkComma;
720                                 len := Length(s);
721                                 while cm do begin
722                                         oc := '';
723                                         No := '';
724                                         sw := false;
725                                         db := false;
726                                         getNumberString;
727                                         Result := addResAnchor(Result);
728                                         cm := checkComma;
729                                 end;
730                         end;
731                 end else begin
732                         //\89½\82©\82µ\82ç\8c©\82Â\82©\82Á\82½\83p\83^\81[\83\93
733                         j := Length(TOKEN[i]) + 1;
734                         oc := '';
735                         No := '';
736                         sw := false;
737                         db := false;
738                         len := Length(s);
739                         getNumberString;
740                         Result := addResAnchor(Result);
741                 end;
742         end;
743         Result := Result + s;
744 end;
745
746 procedure THTMLCreate.ConvertResAnchor(PRes: PResRec);
747 const
748         _HEAD : string = '<a href="../';
749         _TAIL : string = ' target="_blank">';
750         _ST: string = '&st=';
751         _TO: string = '&to=';
752         _STA: string = '&START=';
753         _END: string = '&END=';
754 var
755         i, j, k: Integer;
756         tmp: string;
757         res: string;
758 begin
759         res := PRes.FBody;
760         PRes.FBody := '';
761         i := AnsiPos(_HEAD, res);
762         while i <> 0 do begin
763                 PRes.FBody := PRes.FBody + Copy(res, 1, i -1);
764                 Delete(res, 1, i - 1);
765                 j := AnsiPos(_TAIL, res);
766                 if j = 0 then begin
767                         PRes.FBody := PRes.FBody + res;
768                         Exit;
769                 end;
770                 tmp := Copy(res, 1, j - 1);
771                 Delete(res, 1, j + 16);
772                 if (AnsiPos(_ST, tmp) <> 0) and (AnsiPos(_TO, tmp) <> 0) then begin
773                         Delete(tmp, 1, AnsiPos(_ST, tmp) + 3);
774                         Delete(tmp, AnsiPos(_TO, tmp), Length(tmp));
775                         PRes.FBody := PRes.FBody + '<a href="#' + tmp + '">';
776                 end else if (AnsiPos(_STA, tmp) <> 0) and (AnsiPos(_END, tmp) <> 0) then begin
777                         Delete(tmp, 1, AnsiPos(_STA, tmp) + 6);
778                         Delete(tmp, AnsiPos(_END, tmp), Length(tmp));
779                         PRes.FBody := PRes.FBody + '<a href="#' + tmp + '">';
780                 end else begin
781                         k := LastDelimiter('/', tmp);
782                         Delete(tmp, 1, k);
783                         if AnsiPos('-', tmp) < AnsiPos('"', tmp) then
784                                 Delete(tmp, AnsiPos('-', tmp), Length(tmp))
785                         else
786                                 Delete(tmp, AnsiPos('"', tmp), Length(tmp));
787
788                         PRes.FBody := PRes.FBody + '<a href="#' + tmp + '">';
789                 end;
790                 i := AnsiPos(_HEAD, res);
791         end;
792         PRes.FBody := PRes.FBody + res;
793
794 end;
795
796 //Plugin\82ð\97\98\97p\82·\82éBoard\82Ì\83X\83\8c\83b\83h\82ÌHTML\82ð\8dì\90¬\82µ\82Ädoc\82É\8f\91\82«\8d\9e\82Þ
797 procedure THTMLCreate.CreateUsePluginHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
798 var
799         i: integer;
800         NewReceiveNo: Integer;
801         boardPlugIn : TBoardPlugIn;
802         UserOptionalStyle: string;
803 begin
804         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
805         boardPlugIn             := ThreadItem.ParentBoard.BoardPlugIn;
806         NewReceiveNo    := ThreadItem.NewReceive;
807         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
808         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
809         html.add(boardPlugIn.GetHeader( DWORD( threadItem ),
810                 '<style type="text/css">body {' + UserOptionalStyle + '}</style>' ));
811         html.Add('<p id="idSearch"></p>');
812         html.Flush;
813         
814         for i := 0 to threadItem.Count - 1 do begin
815                 // 1 \82Í\95K\82¸\95\\8e¦
816                 if i <> 0 then begin
817                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
818                         case GikoSys.ResRange of
819                         Ord( grrKoko ):
820                                 if ThreadItem.Kokomade > (i + 1) then
821                                         Continue;
822                         Ord( grrNew ):
823                                 if NewReceiveNo > (i + 1) then
824                                         Continue;
825                         10..65535:
826                                 if (threadItem.Count - i) > GikoSys.ResRange then
827                                         Continue;
828                         end;
829                 end;
830
831                 // \90V\92\85\83}\81[\83N
832                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
833                         try
834                                 if GikoSys.Setting.UseSkin then begin
835                                         if FileExists( GikoSys.GetSkinNewmarkFileName ) then
836                                                 html.Add( LoadFromSkin( GikoSys.GetSkinNewmarkFileName, ThreadItem, ThreadItem.Size ))
837                                         else
838                                                 html.Add( '<a name="new"></a>');
839                                 end else if GikoSys.Setting.UseCSS then begin
840                                         html.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>');
841                                 end else begin
842                                         html.Add('</dl>');
843                                         html.Add('<a name="new"></a>');
844                                         html.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>');
845                                         html.Add('<dl>');
846                                 end;
847                         except
848                                 html.Add( '<a name="new"></a>');
849                         end;
850                 end;
851
852                 // \83\8c\83X
853                 html.Add( boardPlugIn.GetRes( DWORD( threadItem ), i + 1 ));
854
855                 if ThreadItem.Kokomade = (i + 1) then begin
856                         // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾
857                         try
858                                 if GikoSys.Setting.UseSkin then begin
859                                         if FileExists( GikoSys.GetSkinBookmarkFileName ) then
860                                                 html.Add( LoadFromSkin( GikoSys.GetSkinBookmarkFileName, ThreadItem, ThreadItem.Size ))
861                                         else
862                                                 html.Add( '<a name="koko"></a>');
863                                 end else if GikoSys.Setting.UseCSS then begin
864                                         html.Add('<a name="koko"></a><div class="koko">\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</div>');
865                                 end else begin
866                                         html.Add('</dl>');
867                                         html.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>');
868                                         html.Add('<dl>');
869                                 end;
870                         except
871                                 html.Add('<a name="koko"></a>');
872                         end;
873                 end;
874         end;
875
876
877         // \83X\83L\83\93(\83t\83b\83^)
878         html.Add( boardPlugIn.GetFooter( DWORD( threadItem ), '<a name="bottom"></a>' ));
879 end;
880
881
882 procedure THTMLCreate.CreateUseSKINHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList);
883 const
884         KOKO_TAG = '<a name="koko"></a>';
885         NEW_TAG = '<a name="new"></a>';
886 var
887         i: integer;
888         NewReceiveNo: Integer;
889         Res: TResRec;
890         UserOptionalStyle: string;
891         SkinHeader: string;
892         SkinNewRes: string;
893         SkinRes: string;
894         ThreadName : string;
895         ResLink :TResLinkRec;
896 begin
897         NewReceiveNo := ThreadItem.NewReceive;
898         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
899         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
900         ThreadName := ChangeFileExt(ThreadItem.FileName, '');
901         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
902         ResLink.FKey := ThreadName;
903         // \83X\83L\83\93\82Ì\90Ý\92è
904         try
905                 SkinHeader := LoadFromSkin( GikoSys.GetSkinHeaderFileName, ThreadItem, ThreadItem.Size);
906                 if Length( UserOptionalStyle ) > 0 then
907                         SkinHeader := CustomStringReplace( SkinHeader, '</head>',
908                                 '<style type="text/css">body {' + UserOptionalStyle + '}</style></head>');
909                 html.Add( SkinHeader );
910         except
911         end;
912
913         SkinNewRes := LoadFromSkin( GikoSys.GetSkinNewResFileName, ThreadItem, ThreadItem.Size);
914         SkinRes := LoadFromSkin( GikoSys.GetSkinResFileName, ThreadItem, ThreadItem.Size );
915
916         html.Add('<p id="idSearch"></p>'#13#10'<a name="top"></a>');
917         html.Flush;
918
919         for i := 0 to ReadList.Count - 1 do begin
920                 // 1 \82Í\95K\82¸\95\\8e¦
921                 if i <> 0 then begin
922                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
923                         case GikoSys.ResRange of
924                         Ord( grrKoko ):
925                                 if ThreadItem.Kokomade > (i + 1) then
926                                         Continue;
927                         Ord( grrNew ):
928                                 if NewReceiveNo > (i + 1) then
929                                         Continue;
930                         10..65535:
931                                 if (threadItem.Count - i) > GikoSys.ResRange then
932                                         Continue;
933                         end;
934                 end;
935
936                 // \90V\92\85\83}\81[\83N
937                 if (NewReceiveNo = i + 1) or ((NewReceiveNo = 0) and (i = 0)) then begin
938                         if FileExists( GikoSys.GetSkinNewmarkFileName ) then
939                                 html.Add( LoadFromSkin( GikoSys.GetSkinNewmarkFileName, ThreadItem, ThreadItem.Size ))
940                         else
941                                 html.Add( NEW_TAG );
942                 end;
943
944                 if (Trim(ReadList[i]) <> '') then begin
945                         DivideStrLine(ReadList[i], @Res);
946                         AddAnchorTag(@Res);
947                         ConvRes(@Res, @ResLink);
948                         Res.FDateTime := AddBeProfileLink(Res.FDateTime, i + 1);
949
950                         if NewReceiveNo <= (i + 1) then
951                                 // \90V\92\85\83\8c\83X
952                                 html.Add(SkinedRes(SkinNewRes, @Res, IntToStr(i + 1)))
953                         else
954                                 // \92Ê\8fí\82Ì\83\8c\83X
955                                 html.Add(SkinedRes(SkinRes, @Res, IntToStr(i + 1)));
956                 end;
957
958                 if ThreadItem.Kokomade = (i + 1) then begin
959                         // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾
960                         if FileExists( GikoSys.GetSkinBookmarkFileName ) then
961                                 html.Add( LoadFromSkin( GikoSys.GetSkinBookmarkFileName, ThreadItem, ThreadItem.Size ))
962                         else
963                                 html.Add( KOKO_TAG );
964                 end;
965         end;
966
967         html.Add('<a name="bottom"></a>');
968         // \83X\83L\83\93(\83t\83b\83^)
969         html.Add( LoadFromSkin( GikoSys.GetSkinFooterFileName, ThreadItem, ThreadItem.Size ) );
970 end;
971
972 procedure THTMLCreate.CreateUseCSSHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
973 const
974         FORMAT_NOMAIL  = '<a name="%s"></a><div class="header"><span class="no"><a href="menu:%s">%s</a></span>'
975                                         + '<span class="name_label"> \96¼\91O\81F </span> <span class="name"><b>%s</b></span>'
976                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span> <span class="date">%s</span></div>'
977                                         + '<div class="mes">%s</div>';
978
979         FORMAT_SHOWMAIL = '<a name="%s"></a><div class="header"><span class="no"><a href="menu:%s">%s</a></span>'
980                                         + '<span class="name_label"> \96¼\91O\81F </span><a class="name_mail" href="mailto:%s">'
981                                         + '<b>%s</b></a><span class="mail"> [%s]</span><span class="date_label"> \93\8a\8de\93ú\81F</span>'
982                                         + '<span class="date"> %s</span></div><div class="mes">%s</div>';
983
984         FORMAT_NOSHOW = '<a name="%s"></a><div class="header"><span class="no"><a href="menu:%s">%s</a></span>'
985                                         + '<span class="name_label"> \96¼\91O\81F </span><a class="name_mail" href="mailto:%s">'
986                                         + '<b>%s</b></a><span class="date_label"> \93\8a\8de\93ú\81F</span><span class="date"> %s</span></div>'
987                                         + '<div class="mes">%s</div>';
988 var
989         i: integer;
990         No: string;
991         CSSFileName: string;
992         NewReceiveNo: Integer;
993         Res: TResRec;
994         UserOptionalStyle: string;
995         ThreadName :String;
996         ResLink :TResLinkRec;
997 begin
998         NewReceiveNo := ThreadItem.NewReceive;
999         ThreadName := ChangeFileExt(ThreadItem.FileName, '');
1000         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
1001         ResLink.FKey := ThreadName;
1002         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1003         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
1004         CSSFileName := GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName;
1005         if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
1006                 //CSS\8eg\97p
1007                 html.Add('<html><head>');
1008                 html.Add('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1009                 html.Add('<title>' + sTitle + '</title>');
1010                 html.Add('<link rel="stylesheet" href="'+CSSFileName+'" type="text/css">');
1011                 if Length( UserOptionalStyle ) > 0 then
1012                         html.Add('<style type="text/css">body {' + UserOptionalStyle + '}</style>');
1013                 html.Add('</head>'#13#10'<body>');
1014                 html.Add('<a name="top"></a>'#13#10'<p id="idSearch"></p>');
1015                 html.Add('<div class="title">' + sTitle + '</div>');
1016                 html.Flush;
1017                 for i := 0 to ReadList.Count - 1 do begin
1018                         // 1 \82Í\95K\82¸\95\\8e¦
1019                         if i <> 0 then begin
1020                                 // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
1021                                 case GikoSys.ResRange of
1022                                 Ord( grrKoko ):
1023                                         if ThreadItem.Kokomade > (i + 1) then
1024                                                 Continue;
1025                                 Ord( grrNew ):
1026                                         if NewReceiveNo > (i + 1) then
1027                                                 Continue;
1028                                 10..65535:
1029                                         if (threadItem.Count - i) > GikoSys.ResRange then
1030                                                 Continue;
1031                                 end;
1032                         end;
1033
1034                         if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
1035                                 html.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>');
1036                         end;
1037
1038                         if (Trim(ReadList[i]) <> '') then begin
1039                                 No := IntToStr(i + 1);
1040                                 DivideStrLine(ReadList[i], @Res);
1041                                 AddAnchorTag(@Res);
1042                                 ConvRes(@Res, @ResLink);
1043                                 Res.FDateTime := AddBeProfileLink(Res.FDateTime, i + 1);
1044                                 if Res.FMailTo = '' then
1045                                         html.Add(Format(FORMAT_NOMAIL, [No, No, No, Res.FName, Res.FDateTime, Res.FBody]))
1046                                 else if GikoSys.Setting.ShowMail then
1047                                         html.Add(Format(FORMAT_SHOWMAIL, [No, No, No, Res.FMailTo, Res.FName, Res.FMailTo, Res.FDateTime, Res.FBody]))
1048                                 else
1049                                         html.Add(Format(FORMAT_NOSHOW, [No, No, No, Res.FMailTo, Res.FName, Res.FDateTime, Res.FBody]));
1050                         end;
1051
1052                         if ThreadItem.Kokomade = (i + 1) then begin
1053                                 html.Add('<a name="koko"></a><div class="koko">\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</div>');
1054                         end;
1055
1056                 end;
1057
1058                 html.Add('<a name="bottom"></a>');
1059                 html.Add('<a name="last"></a>');
1060                 html.Add('</body></html>');
1061         end;
1062 end;
1063
1064 procedure THTMLCreate.CreateDefaultHTML (html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
1065 var
1066         i: integer;
1067         No: string;
1068         NewReceiveNo: Integer;
1069         Res: TResRec;
1070         ThreadName: String;
1071         ResLink : TResLinkRec;
1072 begin
1073         NewReceiveNo := ThreadItem.NewReceive;
1074         ThreadName := ChangeFileExt(ThreadItem.FileName, '');
1075         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
1076         ResLink.FKey := ThreadName;
1077         html.Add('<html><head>');
1078         html.Add('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1079         html.Add('<title>' + sTitle + '</title></head>');
1080         html.Add('<body TEXT="#000000" BGCOLOR="#EFEFEF" link="#0000FF" alink="#FF0000" vlink="#660099">');
1081         html.Add('<a name="top"></a>');
1082         html.Add('<font size=+1 color="#FF0000">' + sTitle + '</font>');
1083         html.Add('<dl>');
1084         html.Add('<p id="idSearch"></p>');
1085         html.Flush;
1086         for i := 0 to ReadList.Count - 1 do begin
1087                 // 1 \82Í\95K\82¸\95\\8e¦
1088                 if i <> 0 then begin
1089                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
1090                         case GikoSys.ResRange of
1091                         Ord( grrKoko ):
1092                                 if ThreadItem.Kokomade > (i + 1) then
1093                                         Continue;
1094                         Ord( grrNew ):
1095                                 if NewReceiveNo > (i + 1) then
1096                                         Continue;
1097                         10..65535:
1098                                 if (threadItem.Count - i) > GikoSys.ResRange then
1099                                         Continue;
1100                         end;
1101                 end;
1102
1103                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
1104                         html.Add('</dl>');
1105                         html.Add('<a name="new"></a>');
1106                         html.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>');
1107                         html.Add('<dl>');
1108                 end;
1109
1110                 if (Trim(ReadList[i]) <> '') then begin
1111                         No := IntToStr(i + 1);
1112                         DivideStrLine(ReadList[i], @Res);
1113                         AddAnchorTag(@Res);
1114                         ConvRes(@Res, @ResLink);
1115                         Res.FDateTime := AddBeProfileLink(Res.FDateTime, i + 1);
1116                         if Res.FMailTo = '' then
1117                                 html.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 <span class="date">' + Res.FDateTime+ '</span><br><dd>' + Res.Fbody + ' <br><br><br>'#13#10)
1118                         else if GikoSys.Setting.ShowMail then
1119                                 html.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 <span class="date">' + Res.FDateTime+ '</span><br><dd>' + Res.Fbody + ' <br><br><br>'#13#10)
1120                         else
1121                                 html.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 <span class="date">' + Res.FDateTime+ '</span><br><dd>' + Res.Fbody + ' <br><br><br>'#13#10);
1122                 end;
1123                 if ThreadItem.Kokomade = (i + 1) then begin
1124                         html.Add('</dl>');
1125                         html.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>');
1126                         html.Add('<dl>');
1127                 end;
1128         end;
1129         html.Add('</dl>'#13#10'<a name="bottom"></a>'#13#10'</body></html>');
1130 end;
1131
1132 procedure THTMLCreate.CreateHTML2(Browser: TWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
1133 var
1134         ReadList: TStringList;
1135         CSSFileName: string;
1136         FileName: string;
1137         Res: TResRec;
1138         body : TBufferedWebBrowser;
1139 {$IFDEF DEBUG}
1140         st, rt: Cardinal;
1141 {$ENDIF}
1142 begin
1143 {$IFDEF DEBUG}
1144         Writeln('Create HTML');
1145         st := GetTickCount;
1146 {$ENDIF}
1147         if ThreadItem <> nil then begin
1148                 body := TBufferedWebBrowser.Create(Browser, 100);
1149                 try
1150                         body.Open;
1151                         if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1152                                 CreateUsePluginHTML(body, ThreadItem, sTitle);
1153                         end else begin
1154                                 ShortDayNames[1] := '\93ú';               ShortDayNames[2] := '\8c\8e';
1155                                 ShortDayNames[3] := '\89Î';               ShortDayNames[4] := '\90\85';
1156                                 ShortDayNames[5] := '\96Ø';               ShortDayNames[6] := '\8bà';
1157                                 ShortDayNames[7] := '\93y';
1158
1159                                 ReadList := TStringList.Create;
1160                                 try
1161                                         if ThreadItem.IsLogFile then begin
1162                                                 ReadList.BeginUpdate;
1163                                                 FileName := ThreadItem.GetThreadFileName;
1164                                                 ReadList.LoadFromFile(FileName);
1165                                                 ReadList.EndUpdate;
1166                                                 GikoSys.FAbon.IndividualAbon(ReadList, ChangeFileExt(FileName,'.NG'));
1167                                                 GikoSys.FAbon.Execute(ReadList);                //       \82 \82Ú\81`\82ñ\82µ\82Ä
1168                                                 GikoSys.FSelectResFilter.Execute(ReadList); //\83\8c\83X\82Ì\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\82·\82é
1169                                                 if ThreadItem.Title = '' then begin
1170                                                         DivideStrLine(ReadList[0], @Res);
1171                                                         sTitle := Res.FTitle;
1172                                                 end else
1173                                                         sTitle := ThreadItem.Title
1174                                         end else begin
1175                                                 sTitle := CustomStringReplace(ThreadItem.Title, '\81\97\81M', ',');
1176                                         end;
1177                                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1178                                         CSSFileName := GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName;
1179                                         if GikoSys.Setting.UseSkin then begin
1180                                                 CreateUseSKINHTML(body, ThreadItem, ReadList);
1181                                         end else if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
1182                                                 CreateUseCSSHTML(body, ThreadItem, ReadList, sTitle);
1183                                         end else begin
1184                                                 CreateDefaultHTML(body, ThreadItem, ReadList, sTitle);
1185                                         end;
1186                                 finally
1187                                         ReadList.Free;
1188                                 end;
1189                         end;
1190                 finally
1191                         body.Close;
1192                         body.Free;
1193                 end;
1194         end;
1195 {$IFDEF DEBUG}
1196         rt := GetTickCount - st;
1197         Writeln('Done.');
1198         Writeln(IntToStr(rt) + ' ms');
1199 {$ENDIF}
1200 end;
1201
1202 procedure THTMLCreate.CreateHTML3(var html: TStringList; ThreadItem: TThreadItem; var sTitle: string);
1203 var
1204         i: integer;
1205         No: string;
1206         //bufList : TStringList;
1207         ReadList: TStringList;
1208 //      SaveList: TStringList;
1209         CSSFileName: string;
1210         BBSID: string;
1211         FileName: string;
1212         Res: TResRec;
1213         boardPlugIn : TBoardPlugIn;
1214
1215         UserOptionalStyle: string;
1216         SkinHeader: string;
1217         SkinRes: string;
1218         tmp, tmp1: string;
1219         ThreadName: String;
1220         ResLink : TResLinkRec;
1221         function LoadSkin( fileName: string ): string;
1222         begin
1223                 Result := LoadFromSkin( fileName, ThreadItem, ThreadItem.Size );
1224         end;
1225         function ReplaceRes( skin: string ): string;
1226         begin
1227                 Result := SkinedRes( skin, @Res, No );
1228         end;
1229
1230 begin
1231         if ThreadItem <> nil then begin
1232                 CSSFileName := GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName;
1233                 ThreadName := ChangeFileExt(ThreadItem.FileName, '');
1234                 ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
1235                 ResLink.FKey := ThreadName;
1236                 html.Clear;
1237                 html.BeginUpdate;
1238                 //if ThreadItem.IsBoardPlugInAvailable then begin
1239                 if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1240                         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
1241                         //boardPlugIn           := ThreadItem.BoardPlugIn;
1242                         boardPlugIn             := ThreadItem.ParentBoard.BoardPlugIn;
1243                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1244                         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
1245                         try
1246                                 // \95\8e\9a\83R\81[\83h\82Í\83v\83\89\83O\83C\83\93\82É\94C\82¹\82é
1247                                 // \83w\83b\83_
1248                                 tmp := boardPlugIn.GetHeader( DWORD( threadItem ),
1249                                         '<style type="text/css">body {' + UserOptionalStyle + '}</style>' );
1250                                 //\90â\91Î\8eQ\8fÆ\82©\82ç\91\8a\91Î\8eQ\8fÆ\82Ö
1251                                 if GikoSys.Setting.UseSkin then begin
1252                                         tmp1 := './' + GikoSys.Setting.CSSFileName;
1253                                         tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1254                                         tmp1 := CustomStringReplace(tmp1, '\', '/');
1255                                         tmp := CustomStringReplace(tmp, ExtractFilePath(GikoSys.Setting.CSSFileName),  tmp1);
1256                                 end else if GikoSys.Setting.UseCSS then begin
1257                                         tmp1 := './' + CSSFileName;
1258                                         tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1259                                         tmp1 := CustomStringReplace(tmp1, '\', '/');
1260                                         tmp := CustomStringReplace(tmp, CSSFileName,  tmp1);
1261                                 end;
1262                                 html.Append( tmp );
1263
1264                                 for i := 0 to threadItem.Count - 1 do begin
1265
1266                                         // \83\8c\83X
1267                                         Res.FBody := boardPlugIn.GetRes( DWORD( threadItem ), i + 1 );
1268                                         ConvertResAnchor(@Res);
1269                                         html.Append( Res.FBody );
1270
1271                                 end;
1272                                 // \83X\83L\83\93(\83t\83b\83^)
1273                                 html.Append( boardPlugIn.GetFooter( DWORD( threadItem ), '<a name="bottom"></a>' ) );
1274                         finally
1275                         end;
1276                         html.EndUpdate;
1277                         //Exit;
1278                 end else begin
1279                         ShortDayNames[1] := '\93ú';               ShortDayNames[2] := '\8c\8e';
1280                         ShortDayNames[3] := '\89Î';               ShortDayNames[4] := '\90\85';
1281                         ShortDayNames[5] := '\96Ø';               ShortDayNames[6] := '\8bà';
1282                         ShortDayNames[7] := '\93y';
1283                         BBSID := ThreadItem.ParentBoard.BBSID;
1284                         ReadList := TStringList.Create;
1285                         try
1286                                 if ThreadItem.IsLogFile then begin
1287                                         FileName := ThreadItem.GetThreadFileName;
1288                                         ReadList.LoadFromFile(FileName);
1289                                         GikoSys.FAbon.IndividualAbon(ReadList, ChangeFileExt(FileName,'.NG'));
1290                                         GikoSys.FAbon.Execute(ReadList);                //       \82 \82Ú\81`\82ñ\82µ\82Ä
1291                                         GikoSys.FSelectResFilter.Execute(ReadList); //\83\8c\83X\82Ì\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\82·\82é
1292                                         DivideStrLine(ReadList[0], @Res);
1293                                         //Res.FTitle := CustomStringReplace(Res.FTitle, '\81\97\81M', ',');
1294                                         sTitle := Res.FTitle;
1295                                 end else begin
1296                                         sTitle := CustomStringReplace(ThreadItem.Title, '\81\97\81M', ',');
1297                                 end;
1298                                 try
1299                                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1300                                         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
1301
1302                                         if GikoSys.Setting.UseSkin then begin
1303                                                 // \83X\83L\83\93\8eg\97p
1304                                                 // \83X\83L\83\93\82Ì\90Ý\92è
1305                                                 try
1306                                                         SkinHeader := LoadSkin( GikoSys.GetSkinHeaderFileName );
1307                                                         if Length( UserOptionalStyle ) > 0 then
1308                                                                 SkinHeader := CustomStringReplace( SkinHeader, '</head>',
1309                                                                         '<style type="text/css">body {' + UserOptionalStyle + '}</style></head>');
1310                                                         //\90â\91Î\8eQ\8fÆ\82©\82ç\91\8a\91Î\8eQ\8fÆ\82Ö
1311                                                         tmp1 := './' + GikoSys.Setting.CSSFileName;
1312                                                         tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1313                                                         tmp1 := CustomStringReplace(tmp1, '\', '/');
1314                                                         SkinHeader := CustomStringReplace(SkinHeader, ExtractFilePath(GikoSys.Setting.CSSFileName),  tmp1);
1315                                                         html.Append( SkinHeader );
1316                                                 except
1317                                                 end;
1318                                                 try
1319                                                         SkinRes := LoadSkin( GikoSys.GetSkinResFileName );
1320                                                 except
1321                                                 end;
1322                                                 html.Append('<a name="top"></a>');
1323                                                 for i := 0 to ReadList.Count - 1 do begin
1324                                                         if (Trim(ReadList[i]) <> '') then begin
1325                                                                 No := IntToStr(i + 1);
1326
1327                                                                 DivideStrLine(ReadList[i], @Res);
1328                                                                 AddAnchorTag(@Res);
1329                                                                 ConvRes(@Res, @ResLink, true);
1330                                                                 ConvertResAnchor(@Res);
1331
1332                                                                 try
1333                                                                         html.Append( ReplaceRes( SkinRes ) );
1334                                                                 except
1335                                                                 end;
1336                                                         end;
1337
1338                                                 end;
1339                                                 html.Append('<a name="bottom"></a>');
1340                                                 // \83X\83L\83\93(\83t\83b\83^)
1341                                                 try
1342                                                         html.Append( LoadSkin( GikoSys.GetSkinFooterFileName ) );
1343                                                 except
1344                                                 end;
1345                                         end else if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
1346                                                 //CSS\8eg\97p
1347                                                 //CSSFileName := GetAppDir + CSS_FILE_NAME;
1348                                                 html.Append('<html><head>');
1349                                                 html.Append('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1350                                                 html.Append('<title>' + sTitle + '</title>');
1351                                                 //\90â\91Î\8eQ\8fÆ\82©\82ç\91\8a\91Î\8eQ\8fÆ\82Ö
1352                                                 tmp1 := './' + CSSFileName;
1353                                                 tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1354                                                 tmp1 := CustomStringReplace(tmp1, '\', '/');
1355
1356                                                 html.Append('<link rel="stylesheet" href="'+tmp1+'" type="text/css">');
1357                                                 if Length( UserOptionalStyle ) > 0 then
1358                                                         html.Append('<style type="text/css">body {' + UserOptionalStyle + '}</style>');
1359                                                 html.Append('</head>');
1360                                                 html.Append('<body>');
1361                                                 html.Append('<a name="top"></a>');
1362                                                 html.Append('<div class="title">' + sTitle + '</div>');
1363                                                 for i := 0 to ReadList.Count - 1 do begin
1364                                                         if (Trim(ReadList[i]) <> '') then begin
1365                                                                 No := IntToStr(i + 1);
1366                                                                 DivideStrLine(ReadList[i], @Res);
1367                                                                 AddAnchorTag(@Res);
1368                                                                 ConvRes(@Res, @ResLink, true);
1369                                                                 ConvertResAnchor(@Res);
1370                                                                 if Res.FMailTo = '' then
1371                                                                         html.Append('<a name="' + No + '"></a>'
1372                                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span> '
1373                                                                                                         + '<span class="name_label">\96¼\91O\81F</span> '
1374                                                                                                         + '<span class="name"><b>' + Res.FName + '</b></span> '
1375                                                                                                         + '<span class="date_label">\93\8a\8de\93ú\81F</span> '
1376                                                                                                         + '<span class="date">' + Res.FDateTime+ '</span></div>'
1377                                                                                                                                                                                                 + '<div class="mes">' + Res.FBody + ' </div>')
1378                                                                 else if GikoSys.Setting.ShowMail then
1379                                                                         html.Append('<a name="' + No + '"></a>'
1380                                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span>'
1381                                                                                                                                                                                                 + '<span class="name_label"> \96¼\91O\81F </span>'
1382                                                                                                         + '<a class="name_mail" href="mailto:' + Res.FMailTo + '">'
1383                                                                                                         + '<b>' + Res.FName + '</b></a><span class="mail"> [' + Res.FMailTo + ']</span>'
1384                                                                                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span>'
1385                                                                                                         + '<span class="date"> ' + Res.FDateTime+ '</span></div>'
1386                                                                                                         + '<div class="mes">' + Res.FBody + ' </div>')
1387                                                                 else
1388                                                                         html.Append('<a name="' + No + '"></a>'
1389                                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span>'
1390                                                                                                         + '<span class="name_label"> \96¼\91O\81F </span>'
1391                                                                                                         + '<a class="name_mail" href="mailto:' + Res.FMailTo + '">'
1392                                                                                                         + '<b>' + Res.FName + '</b></a>'
1393                                                                                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span>'
1394                                                                                                         + '<span class="date"> ' + Res.FDateTime+ '</span></div>'
1395                                                                                                                                                                                                 + '<div class="mes">' + Res.FBody + ' </div>');
1396                                                         end;
1397                                                 end;
1398                                                 html.Append('<a name="bottom"></a>');
1399                                                 html.Append('<a name="last"></a>');
1400                                                 html.Append('</body></html>');
1401                                         end else begin
1402                                                 //CSS\94ñ\8eg\97p
1403                                                 html.Append('<html><head>');
1404                                                 html.Append('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1405                                                 html.Append('<title>' + sTitle + '</title></head>');
1406                                                 html.Append('<body TEXT="#000000" BGCOLOR="#EFEFEF" link="#0000FF" alink="#FF0000" vlink="#660099">');
1407                                                 html.Append('<a name="top"></a>');
1408                                                 html.Append('<font size=+1 color="#FF0000">' + sTitle + '</font>');
1409                                                 html.Append('<dl>');
1410                                                 for i := 0 to ReadList.Count - 1 do begin
1411                                                         if (Trim(ReadList[i]) <> '') then begin
1412                                                                 No := IntToStr(i + 1);
1413                                                                 DivideStrLine(ReadList[i], @Res);
1414                                                                 AddAnchorTag(@Res);
1415                                                                 ConvRes(@Res, @ResLink, true);
1416                                                                 ConvertResAnchor(@Res);
1417                                                                 if Res.FMailTo = '' then
1418                                                                         html.Append('<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>')
1419                                                                 else if GikoSys.Setting.ShowMail then
1420                                                                         html.Append('<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>')
1421                                                                 else
1422                                                                         html.Append('<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>');
1423                                                         end;
1424                                                 end;
1425                                                 html.Append('</dl>');
1426                                                 html.Append('<a name="bottom"></a>');
1427                                                 html.Append('</body></html>');
1428                                         end;
1429                                 finally
1430                                         html.EndUpdate;
1431                                 end;
1432                         finally
1433                                 ReadList.Free;
1434                         end;
1435                 end;
1436         end;
1437 end;
1438
1439 procedure THTMLCreate.SetResPopupText(Hint : TResPopup; threadItem: TThreadItem; StNum, ToNum: Integer; Title, First: Boolean);
1440 var
1441         i: Integer;
1442         tmp: string;
1443         FileName: string;
1444         Line: Integer;
1445
1446         wkInt: Integer;
1447
1448         Res: TResRec;
1449         Header: string;
1450         Body: string;
1451     boardPlugIn : TBoardPlugIn;
1452 begin
1453         try
1454                 if StNum > ToNum then begin
1455                         wkInt := StNum;
1456                         StNum := ToNum;
1457                         ToNum := wkInt;
1458                 end;
1459
1460                 //\8dÅ\91å10\83\8c\83X\82Ü\82Å\95\\8e¦
1461                 if StNum + MAX_POPUP_RES < ToNum then
1462                         ToNum := StNum + MAX_POPUP_RES;
1463
1464                 //\83^\83C\83g\83\8b\95\\8e¦
1465                 if Title then
1466                                 if ThreadItem <> nil then
1467                                         Hint.Title := ThreadItem.Title;
1468
1469         if ThreadItem <> nil then begin
1470             //if ThreadItem.IsBoardPlugInAvailable then begin
1471             if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1472                 //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
1473                 //boardPlugIn           := ThreadItem.BoardPlugIn;
1474                 boardPlugIn             := ThreadItem.ParentBoard.BoardPlugIn;
1475
1476                 // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1477                 // \95\8e\9a\83R\81[\83h\82Í\83v\83\89\83O\83C\83\93\82É\94C\82¹\82é
1478                 for i := StNum to ToNum do begin
1479                     Line := i;
1480                                         //\82±\82±\82Å\82Q\82¿\82á\82ñ\82Ë\82é\82Ìdat\82Ì\8c`\8e®\82Å\82P\8ds\93Ç\82Ý\8d\9e\82ß\82ê\82Î¥¥¥\81B\81«\93Ç\82ß\82é\82æ\82¤\82É\82È\82Á\82½
1481                                         tmp := boardPlugIn.GetDat( DWORD( threadItem ), i );
1482                     if (tmp <> '') And ( not GikoSys.FAbon.CheckAbonPopupRes(tmp) And( not GikoSys.FAbon.CheckIndividualAbonList(line))) then begin
1483                                                 DivideStrLine(tmp, @Res);
1484                         if (GikoSys.Setting.ShowMail = false) or (Length(res.FMailTo) = 0) then
1485                                 Header := IntToStr(Line) + ' \96¼\91O\81F ' + Res.FName + ' \93\8a\8de\93ú\81F ' + Res.FDateTime
1486                         else
1487                                 Header := IntToStr(Line) + ' \96¼\91O\81F ' + Res.FName + ' [' + res.FMailTo + '] \93\8a\8de\93ú\81F ' + Res.FDateTime;
1488                                                 Header := DeleteFontTag(Header);
1489                                                 Header := CustomStringReplace(Header, '<br>', '',true);
1490
1491                                                 Body := CustomStringReplace(Res.FBody, '<br> ', #10,true);
1492                                                 Body := CustomStringReplace(Body, '<br>', #10,true);
1493                         Body := CustomStringReplace(Body, '</a>', '',true);
1494                                                 Body := THTMLCreate.DeleteLink(Body);
1495                         Body := CustomStringReplace(Body, '&lt;', '<');
1496                         Body := CustomStringReplace(Body, '&gt;', '>');
1497                         Body := CustomStringReplace(Body, '&quot;', '"');
1498                         Body := CustomStringReplace(Body, '&amp;', '&');
1499                         Body := CustomStringReplace(Body, '&nbsp;', ' ');
1500
1501                                                 Hint.Add(Header, Body);
1502                                         end;
1503                                 end;
1504                         end else begin
1505                                 for i := StNum to ToNum do begin
1506                                         Line := i;
1507                                         FileName := ThreadItem.FilePath;
1508                                         tmp := GikoSys.ReadThreadFile(FileName, Line);
1509                                         if (tmp <> '') And ( not GikoSys.FAbon.CheckAbonPopupRes(tmp) And( not GikoSys.FAbon.CheckIndividualAbonList(line))) then begin
1510                                                 DivideStrLine(tmp, @Res);
1511                                                 if (GikoSys.Setting.ShowMail = false) or (Length(res.FMailTo) = 0) then
1512                                                         Header := IntToStr(Line) + ' \96¼\91O\81F ' + Res.FName + ' \93\8a\8de\93ú\81F ' + Res.FDateTime
1513                                                 else
1514                                                         Header := IntToStr(Line) + ' \96¼\91O\81F ' + Res.FName + ' [' + res.FMailTo + '] \93\8a\8de\93ú\81F ' + Res.FDateTime;
1515
1516                                                 Body := DeleteFontTag(Res.FBody);
1517                                                 Body := CustomStringReplace(Body, '<br> ', #10,true);
1518                                                 Body := CustomStringReplace(Body, '<br>', #10,true);
1519                                                 Body := CustomStringReplace(Body, '</a>', '',true);
1520                                                 Body := THTMLCreate.DeleteLink(Body);
1521                                                 Body := CustomStringReplace(Body, '&lt;', '<');
1522                                                 Body := CustomStringReplace(Body, '&gt;', '>');
1523                                                 Body := CustomStringReplace(Body, '&quot;', '"');
1524                                                 Body := CustomStringReplace(Body, '&amp;', '&');
1525                                                  Body := CustomStringReplace(Body, '&nbsp;', ' ');
1526                                                 Hint.Add(Header, Body);
1527                                         end;
1528                                 end;
1529                         end;
1530                 end;
1531         finally
1532         end;
1533 end;
1534
1535 //\83\8a\83\93\83N\82Ì\95\8e\9a\97ñ\82©\82ç\83\8c\83X\83|\83b\83v\83A\83b\83v\97p\82ÌURL\82É\95Ï\8a·\82·\82é
1536 class function THTMLCreate.GetRespopupURL(AText, AThreadURL : string): string;
1537 var
1538         wkInt: Integer;
1539 begin
1540         Result := '';
1541         if Pos('about:blank..', AText) = 1 then begin
1542                 wkInt := LastDelimiter( '/', AThreadURL );
1543                 if Pos( '?', Copy( AThreadURL, wkInt, MaxInt ) ) = 0 then begin
1544                         // Thread.URL \82Í PATH_INFO \93n\82µ
1545                         Result := Copy( AThreadURL, 1,  LastDelimiter( '/', AThreadURL ) );
1546                         wkInt := LastDelimiter( '/', AText );
1547                         if Pos( '?', Copy( AText, wkInt, MaxInt ) ) = 0 then
1548                                 // Text \82à PATH_INFO \93n\82µ
1549                                 Result := Result + Copy( AText, LastDelimiter( '/', AText ) + 1, MaxInt )
1550                         else
1551                                 // Text \82Í QUERY_STRING \93n\82µ
1552                                 Result := Result + Copy( AText, LastDelimiter( '?', AText ) + 1, MaxInt );
1553                 end else begin
1554                         // Thread.URL \82Í QUERY_STRING \93n\82µ
1555                         Result := Copy( AThreadURL, 1,  LastDelimiter( '?', AThreadURL ) );
1556                         wkInt := LastDelimiter( '/', AText );
1557                         if Pos( '?', Copy( AText, wkInt, MaxInt ) ) = 0 then begin
1558                                 // Text \82Í PATH_INFO \93n\82µ
1559                                 // URL \82É\94Â\82Æ\83L\81[\82ª\91«\82ç\82È\82¢\82Ì\82Å Text \82©\82ç\92¸\91Õ\82·\82é
1560                                 wkInt := LastDelimiter( '/', Copy( AText, 1, wkInt - 1 ) );
1561                                 wkInt := LastDelimiter( '/', Copy( AText, 1, wkInt - 1 ) );
1562                                 Result := Copy( Result, 1, Length( Result ) - 1 ) + Copy( AText, wkInt, MaxInt );
1563                         end else begin
1564                                 // Text \82à QUERY_STRING \93n\82µ
1565                                 Result := Result + Copy( AText, LastDelimiter( '?', AText ) + 1, MaxInt )
1566                         end;
1567                 end;
1568         end else if Pos('about:blank/bbs/', AText) = 1 then begin
1569                 //\82µ\82½\82ç\82ÎJBBS\82Ì\8ed\95Ï\82Ì\8bz\8eû
1570                 AText := CustomStringReplace(AText, 'about:blank/bbs/', 'about:blank../../bbs/');
1571                 Result := GetRespopupURL(AText, AThreadURL);
1572         end else begin
1573                 Result := AText;
1574         end;
1575
1576 end;
1577 //\8ew\92è\82µ\82½\83p\83X\82É\83X\83L\83\93\82à\82µ\82­\82ÍCSS\82Ì\83t\83@\83C\83\8b\82Ì\83R\83s\81[\82ð\8dì\82é
1578 class procedure THTMLCreate.SkinorCSSFilesCopy(path: string);
1579 var
1580         tmp, tmpD, tmpF: string;
1581         current: string;
1582         dirs: TStringList;
1583         files: TStringList;
1584         i, j: Integer;
1585 begin
1586         if GikoSys.Setting.UseSkin then begin
1587                 current := ExtractFilePath(GikoSys.GetSkinDir);
1588                 tmp := GikoSys.Setting.CSSFileName;
1589         end else if GikoSys.Setting.UseCSS then begin
1590                 current := ExtractFilePath(GikoSys.GetStyleSheetDir);
1591                 tmp := ExtractFilePath(GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName);
1592         end;
1593         dirs := TStringList.Create;
1594         try
1595                 dirs.Add(tmp);
1596                 if tmp <> current then begin
1597                         GikoSys.GetDirectoryList(current, '*.*', dirs, true);
1598                         for i := 0 to dirs.Count - 1 do begin
1599                                 files := TStringList.Create;
1600                                 try
1601                                         files.BeginUpdate;
1602                                         gikoSys.GetFileList(dirs[i], '*.*', files, true);
1603                                         files.EndUpdate;
1604                                         tmpD := CustomStringReplace(dirs[i], GikoSys.GetConfigDir, path);
1605                                         if (AnsiPos(dirs[i], tmp) <> 0) and not (DirectoryExists(tmpD)) then
1606                                                 ForceDirectories(tmpD);
1607
1608                                         if(dirs[i] = tmp) and (dirs[i] <> current) then begin
1609                                                 for j := 0 to files.Count - 1 do begin
1610                                                         tmpF := CustomStringReplace(files[j], GikoSys.GetConfigDir, path);
1611                                                         if not FileExists(tmpF) then begin
1612                                                                 CopyFile(PChar(files[j]), PChar(tmpF),True);
1613                                                         end;
1614                                                 end;
1615                                         end;
1616                                 finally
1617                                         files.Free;
1618                                 end;
1619                         end;
1620                 end else begin
1621                         tmpD := CustomStringReplace(dirs[0], GikoSys.GetConfigDir, path);
1622                         if not DirectoryExists(tmpD) then
1623                                 ForceDirectories(tmpD);
1624                         tmpF := CustomStringReplace(GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName
1625                                         , GikoSys.GetConfigDir, path);
1626                         if not FileExists(tmpF) then begin
1627                                 CopyFile(PChar(GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName)
1628                                         , PChar(tmpF), True);
1629                         end;
1630                 end;
1631         finally
1632                 dirs.Free;
1633         end;
1634 end;{!
1635 \brief dat\83t\83@\83C\83\8b\82Ì\88ê\83\89\83C\83\93\82ð\95ª\89ð
1636 \param Line dat\83t\83@\83C\83\8b\82ð\8d\\90¬\82·\82é 1 \8ds
1637 \return     \83\8c\83X\8fî\95ñ
1638 }
1639 class procedure THTMLCreate.DivideStrLine(Line: string; PRes: PResRec);
1640 const
1641         delimiter = '<>';
1642 var
1643         pds, pde : PChar;
1644         pss, pse : PChar;
1645         ppos : PChar;
1646 begin
1647         //\8cÅ\92è
1648         PRes.FType := glt2chNew;
1649
1650         pss := PChar(Line);
1651         pse := pss + Length(Line);
1652         pds := PChar(delimiter);
1653         pde := pds + Length(delimiter);
1654
1655         ppos := AnsiStrPosEx(pss, pse, pds, pde);
1656         if (ppos = nil) then begin
1657                 Line := CustomStringReplace(Line, '<>', '&lt;&gt;');
1658                 Line := CustomStringReplace(Line, ',', '<>');
1659                 Line := CustomStringReplace(Line, '\81\97\81M', ',');
1660         end;
1661         //Trim\82µ\82Ä\82Í\82¢\82¯\82È\82¢\8bC\82ª\82·\82é\81@by\82à\82\82ã
1662         PRes.FName := RemoveToken(Line, delimiter);
1663         PRes.FMailTo := RemoveToken(Line, delimiter);
1664         PRes.FDateTime := RemoveToken(Line, delimiter);
1665         PRes.FBody := RemoveToken(Line, delimiter);
1666         //\82Q\82¿\82á\82ñ\82Ë\82é\82Æ\82©\82¾\82Æ\81A\96{\95\82Ì\90æ\93ª\82É\82P\82Â\94¼\8ap\8bó\94\92\82ª\93ü\82Á\82Ä\82¢\82é\82Ì\82Å\8dí\8f\9c\82·\82é
1667         //\91¼\82Ì\8cf\8e¦\94Â\82Å\81A\83\8c\83X\8e©\91Ì\82Ì\8bó\94\92\82©\82à\82µ\82ê\82È\82¢\82¯\82Ç\82»\82ê\82Í\92ú\82ß\82é
1668         PRes.FBody := TrimLeft(PRes.FBody);
1669         //\8bó\82¾\82Æ\96â\91è\82ª\8bN\82«\82é\82©\82ç\81A\8bó\94\92\82ð\90Ý\92è\82·\82é
1670         if PRes.FBody = '' then
1671                 PRes.FBody := '&nbsp;';
1672
1673         PRes.FTitle := RemoveToken(Line, delimiter);
1674 end;
1675
1676 {!
1677 \brief HTML \82©\82ç\83A\83\93\83J\81[\83^\83O\82ð\8dí\8f\9c
1678 \param s \8c³\82É\82È\82é HTML
1679 \return  \83A\83\93\83J\81[\83^\83O\82ª\8dí\8f\9c\82³\82ê\82½ HTML
1680 }
1681 class function THTMLCreate.DeleteLink(const s: string): string;
1682 var
1683         s1: string;
1684         s2: string;
1685         idx: Integer;
1686         i: Integer;
1687 begin
1688         i := 0;
1689         Result := '';
1690         while True do begin
1691                 s1 := GikoSys.GetTokenIndex(s, '<a href="', i);
1692                 s2 := GikoSys.GetTokenIndex(s, '<a href="', i + 1);
1693
1694                 idx := Pos('">', s1);
1695                 if idx <> 0 then
1696                         Delete(s1, 1, idx + 1);
1697                 idx := Pos('">', s2);
1698                 if idx <> 0 then
1699                         Delete(s2, 1, idx + 1);
1700
1701                 Result := Result + s1 + s2;
1702
1703                 if s2 = '' then
1704                         Break;
1705
1706                 inc(i, 2);
1707         end;
1708 end;
1709
1710 constructor TBufferedWebBrowser.Create(Browser: TWebBrowser; BuffSize: Integer);
1711 begin
1712         inherited Create;
1713         Self.Sorted := False;
1714         if (Browser = nil) then
1715                 Raise  Exception.Create('Browser is NULL');
1716         FBrowser := Browser;
1717
1718         // \83o\83b\83t\83@\82·\82é\8ds\90\94\82ð
1719         if (BuffSize < 0) then begin
1720                 FBuffSize := 100;
1721         end else begin
1722                 FBuffSize := BuffSize;
1723         end;
1724         Self.Capacity := FBuffSize + 10;
1725 end;
1726 procedure TBufferedWebBrowser.Open;
1727 begin
1728         FBrowserDoc := Idispatch( olevariant(FBrowser.ControlInterface).Document);
1729         FBrowserDoc.open;
1730         FBrowserDoc.charset := 'Shift_JIS';
1731 end;
1732 procedure TBufferedWebBrowser.Close;
1733 begin
1734         Self.Flush;
1735         try
1736                 FBrowserDoc.Close;
1737         except
1738         end;
1739         FBrowser := nil;
1740 end;
1741 function TBufferedWebBrowser.Add(const S: string): Integer;
1742 begin
1743         Result := inherited Add(TrimRight(s));
1744         if (Self.Count > FBuffSize) then begin
1745                 FBrowserDoc.Write(Self.Text);
1746                 Self.Clear;
1747         end;
1748 end;
1749 procedure TBufferedWebBrowser.Flush ;
1750 begin
1751         if (Self.Count > 0) then begin
1752                 FBrowserDoc.Write(Self.Text);
1753                 Self.Clear;
1754         end;
1755 end;
1756 destructor TBufferedWebBrowser.Destory;
1757 begin
1758         try
1759                 if (FBrowserDoc <> 0) then begin
1760                         FBrowserDoc.close;
1761                         FBrowserDoc := 0;
1762                 end;
1763         except
1764         end;
1765         inherited;
1766 end;
1767
1768 initialization
1769          HTMLCreater := THTMLCreate.Create;
1770
1771 finalization
1772         if HTMLCreater <> nil then begin
1773                 HTMLCreater.Free;
1774                 HTMLCreater := nil;
1775         end;
1776
1777 end.