OSDN Git Service

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