OSDN Git Service

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