OSDN Git Service

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