OSDN Git Service

・スレタイの特定ワードを非表示にする機能に「©bbspink.com」も追加
[gikonavigoeson/gikonavi.git] / GikoSystem.pas
index 7dc995a..827e109 100644 (file)
@@ -15,7 +15,7 @@ uses
        {HttpApp,} URLMon, IdGlobal, IdURI, {Masks,}
        Setting, BoardGroup, gzip, Dolib, bmRegExp, AbonUnit,
        ExternalBoardManager, ExternalBoardPlugInMain,
-       GikoBayesian, GikoMessage;
+       GikoBayesian, GikoMessage, Belib;
 
 type
        TVerResourceKey = (
@@ -112,6 +112,7 @@ type
                FBayesian       : TGikoBayesian;        //!< \83x\83C\83W\83A\83\93\83t\83B\83\8b\83^
                FVersion : String;                    //!< \83t\83@\83C\83\8b\83o\81[\83W\83\87\83\93
                FGikoMessage: TGikoMessage;
+        FBelib: TBelib;
                //! \82 \82é\83Z\83p\83\8c\81[\83^\82Å\8bæ\90Ø\82ç\82ê\82½\95\8e\9a\97ñ\82©\82ç\82\8e\94Ô\96Ú\82Ì\95\8e\9a\97ñ\82ð\8eæ\82è\8fo\82·
                function ChooseString(const Text, Separator: string; Index: integer): string;
         //! \88ê\8e\9e\83t\83@\83C\83\8b\82©\82ç\82Ì\95\9c\8b\8c
@@ -127,13 +128,10 @@ type
                property ResRange : Longint read FResRange write FResRange;
                //! \83o\81[\83W\83\87\83\93\8fî\95ñ
                property Version : String read FVersion;
-//             function MsgBox(Msg: string; Title: string; Flags: Longint): integer; overload;
-//             function MsgBox(Handle: THandle; Msg: string; Title: string; Flags: Longint): integer; overload;
                function IsNumeric(s: string): boolean;
                function IsFloat(s: string): boolean;
                function DirectoryExistsEx(const Name: string): Boolean;
                function ForceDirectoriesEx(Dir: string): Boolean;
-//             function GetVersion: string;
 
                function GetBoardFileName: string;
                function GetCustomBoardFileName: string;
@@ -142,6 +140,7 @@ type
                function GetTempFolder: string;
                function GetSentFileName: string;
                function GetConfigDir: string;
+        function GetNGWordsDir: string;
                function GetSkinDir: string;
                function GetSkinHeaderFileName: string;
                function GetSkinFooterFileName: string;
@@ -168,6 +167,7 @@ type
                function DivideSubject(Line: string): TSubjectRec;
                property Setting: TSetting read FSetting write FSetting;
                property Dolib: TDolib read FDolib write FDolib;
+               property Belib: TBelib read FBelib write FBelib;
 
                function UrlToID(url: string): string;
                function UrlToServer(url: string): string;
@@ -184,10 +184,11 @@ type
 
                procedure MenuFont(Font: TFont);
 
-               function RemoveToken(var s:string; const delimiter:string):string;
+//             function RemoveToken(var s:string; const delimiter:string):string;
                function GetTokenIndex(s: string; delimiter: string; index: Integer): string;
 
                function GetShortName(const LongName: string; ALength: integer): string;
+               function TrimThreadTitle(const SrcTitle: string): string;
                function BoolToInt(b: Boolean): Integer;
                function IntToBool(i: Integer): Boolean;
                function GzipDecompress(ResStream: TStream; ContentEncoding: string): string;
@@ -216,13 +217,11 @@ type
                procedure GetPopupResNumber(URL : string; var stRes, endRes : Int64);
 
                property Bayesian : TGikoBayesian read FBayesian write FBayesian;
-               function GetSameIDResAnchor(const AID : string; ThreadItem: TThreadItem; limited: boolean):string; overload;
-               function GetSameIDResAnchor(AIDNum : Integer; ThreadItem: TThreadItem; limited: boolean):string; overload;
+        function CreateResAnchor(var Numbers: TStringList; ThreadItem: TThreadItem; limited: Integer):string;
                procedure GetSameIDRes(const AID : string; ThreadItem: TThreadItem;var body: TStringList); overload;
                procedure GetSameIDRes(AIDNum : Integer; ThreadItem: TThreadItem;var body: TStringList); overload;
-               function GetSameIDResCount(const AID : string; ThreadItem: TThreadItem):Integer; overload;
-               function GetSameIDResCount(AIDNum : Integer; ThreadItem: TThreadItem):Integer; overload;
-
+        function GetResID(AIDNum: Integer; ThreadItem: TThreadItem): String;
+        function ExtructResID(ADateStr: String): String;
                //! \92P\8cê\89ð\90Í
                procedure SpamCountWord( const text : string; wordCount : TWordCount );
                //! \8aw\8fK\83N\83\8a\83A
@@ -231,8 +230,6 @@ type
                procedure SpamLearn( wordCount : TWordCount; isSpam : Boolean );
                //! \83X\83p\83\80\93x\90\94
                function SpamParse( const text : string; wordCount : TWordCount ) : Extended;
-               //\88ø\90\94\82ª\81A\93ú\95t\82Å\82à\8e\9e\8d\8f\82Å\82à\82È\82¢\82±\82Æ\82ð\92²\82×\82é
-               function NotDateorTimeString(const AStr : string): boolean;
 
                //! \88ø\90\94\82É\91\97\82ç\82ê\82Ä\82«\82½\93ú\95t/ID\95\94\82ÉBE\82Ì\95\8e\9a\97ñ\82ª\82 \82Á\82½\82ç\81A\83v\83\8d\83t\83@\83C\83\8b\82Ö\82Ì\83\8a\83\93\83N\82ð\92Ç\89Á
                function AddBeProfileLink(AID : string; ANum: Integer): string;
@@ -253,6 +250,25 @@ type
         function CanUser32DLL: Boolean;
         //! OE\88ø\97p\95\84\8eæ\93¾
         function GetOEIndentChar : string;
+        //! \92u\8a·\90Ý\92è\83t\83@\83C\83\8b\8eæ\93¾
+        function GetReplaceFileName: String;
+        //! \83C\83\93\83f\83b\83N\83X\82É\82È\82¢dat\81i\82Í\82®\82êdat\81j\82Ì\92Ç\89Á
+        procedure AddOutofIndexDat(Board: TBoard; DatList: TStringList; AllCreate: boolean = True);
+        //! \83t\83@\83C\83\8b\96¼\82©\82ç\82Ì\83X\83\8c\83b\83h\8dì\90¬\93ú\82Ì\8eæ\93¾
+        function GetCreateDateFromName(FileName: String): TDateTime;
+        function GetExtpreviewFileName: String;
+
+        procedure ShowRefCount(msg: String; unk: IUnknown);
+        //! \96`\8c¯\82Ì\8f\91Cookie\8eæ\93¾
+        function GetBoukenCookie(AURL: String): String;
+        //! \96`\8c¯\82Ì\8f\91Cookie\90Ý\92è
+        procedure SetBoukenCookie(ACookieValue, ADomain: String);
+        //! \96`\8c¯\82Ì\8f\91Cookie\8dí\8f\9c
+        procedure DelBoukenCookie(ADomain: String);
+        //! \96`\8c¯\82Ì\8f\91Domain\88ê\97\97\8eæ\93¾
+        procedure GetBoukenDomain(var ADomain: TStringList);
+        //! \96`\8c¯\82Ì\8f\91\83h\83\81\83C\83\93\96¼Cookie\8eæ\93¾
+        function GetBouken(AURL: String; var Domain: String): String;
        end;
 
 var
@@ -262,7 +278,7 @@ const
        ZERO_DATE: Integer      = 25569;
        BETA_VERSION_NAME_E = 'beta';
        BETA_VERSION_NAME_J = 'ÊÞÀ';
-       BETA_VERSION                            = 54;
+       BETA_VERSION                            = 68;
        BETA_VERSION_BUILD      = '';                           //!< debug\94Å\82È\82Ç
        APP_NAME                                                = 'gikoNavi';
        BE_PHP_URL = 'http://be.2ch.net/test/p.php?i=';
@@ -272,7 +288,7 @@ implementation
 
 uses
        Giko, RoundData, Favorite, Registry, HTMLCreate, MojuUtils, Sort, YofUtils,
-       IniFiles, DateUtils;
+       IniFiles, DateUtils, SkinFiles;
 
 const
        FOLDER_INDEX_VERSION                                    = '1.01';
@@ -281,6 +297,7 @@ const
        NGWORDs_DIR_NAME : String               = 'NGwords';
 
        READ_PATH: string =                     '/test/read.cgi/';
+    HTML_READ_PATH: string =        '/test/read.html/';
        OLD_READ_PATH: string =         '/test/read.cgi?';
        KAKO_PATH: string =                     '/kako/';
 
@@ -303,8 +320,10 @@ const
 // *************************************************************************
 constructor TGikoSys.Create;
 begin
+    Inherited;
        FSetting := TSetting.Create;
        FDolib := TDolib.Create;
+    FBelib := TBelib.Create;
        FAWKStr := TAWKStr.Create(nil);
        if DirectoryExists(GetConfigDir) = false then begin
                CreateDir(GetConfigDir);
@@ -341,18 +360,6 @@ var
        i: Integer;
        FileList: TStringList;
 begin
-       //\83X\83\8c\83b\83h\83f\81[\83^\83t\83@\83C\83\8b\82ð\8dX\90V
-//     FlashExitWrite;
-
-//     FExitWrite.Free;
-       FBayesian.Free;
-       FAWKStr.Free;
-       FSetting.Free;
-       FDolib.Free;
-       FAbon.Free;
-       FSelectResFilter.Free;
-    FGikoMessage.Free;
-       //FBoardURLList.Free;
        //\83e\83\93\83|\83\89\83\8aHTML\82ð\8dí\8f\9c
        FileList := TStringList.Create;
        try
@@ -365,6 +372,14 @@ begin
        finally
                FileList.Free;
        end;
+    FreeAndNil(FGikoMessage);
+       FreeAndNil(FBayesian);
+       FreeAndNil(FSelectResFilter);
+       FreeAndNil(FAbon);
+       FreeAndNil(FAWKStr);
+    FreeAndNil(FBelib);
+       FreeAndNil(FDolib);
+       FreeAndNil(FSetting);
        inherited;
 end;
 
@@ -461,6 +476,12 @@ begin
        Result := Setting.GetConfigDir;
 end;
 
+function TGikoSys.GetNGWordsDir: string;
+begin
+       Result := Setting.GetConfigDir + NGWORDs_DIR_NAME;
+end;
+
+
 //! \83X\83^\83C\83\8b\83V\81[\83g\83t\83H\83\8b\83_
 function TGikoSys.GetStyleSheetDir: string;
 begin
@@ -476,37 +497,37 @@ end;
 //! Skin:\83w\83b\83_\82Ì\83t\83@\83C\83\8b\96¼
 function TGikoSys.GetSkinHeaderFileName: string;
 begin
-       Result := Setting.GetSkinHeaderFileName;
+       Result := Setting.SkinFiles.GetSkinHeaderFileName;
 end;
 
 //! Skin:\83t\83b\83^\82Ì\83t\83@\83C\83\8b\96¼
 function TGikoSys.GetSkinFooterFileName: string;
 begin
-       Result := Setting.GetSkinFooterFileName;
+       Result := Setting.SkinFiles.GetSkinFooterFileName;
 end;
 
 //! Skin:\90V\92\85\83\8c\83X\82Ì\83t\83@\83C\83\8b\96¼
 function TGikoSys.GetSkinNewResFileName: string;
 begin
-       Result := Setting.GetSkinNewResFileName;
+       Result := Setting.SkinFiles.GetSkinNewResFileName;
 end;
 
 //! Skin:\94ñ\90V\92\85\83\8c\83X\82Ì\83t\83@\83C\83\8b\96¼
 function TGikoSys.GetSkinResFileName: string;
 begin
-       Result := Setting.GetSkinResFileName;
+       Result := Setting.SkinFiles.GetSkinResFileName;
 end;
 
 //! Skin:\82µ\82¨\82è(\82±\82±\82Ü\82Å\93Ç\82ñ\82¾)\82Ì\83t\83@\83C\83\8b\96¼
 function TGikoSys.GetSkinBookmarkFileName: string;
 begin
-       Result := Setting.GetSkinBookmarkFileName;
+       Result := Setting.SkinFiles.GetSkinBookmarkFileName;
 end;
 
 //! Skin:\82µ\82¨\82è(\90V\92\85\83\8c\83X)\82Ì\83t\83@\83C\83\8b\96¼
 function TGikoSys.GetSkinNewmarkFileName: string;
 begin
-       Result := Setting.GetSkinNewmarkFileName;
+       Result := Setting.SkinFiles.GetSkinNewmarkFileName;
 end;
 
 //! UserAgent\8eæ\93¾
@@ -565,51 +586,62 @@ var
        i: Integer;
        Rec: TIndexRec;
        UnRead: Integer;
-       ResRec: TResRec;
        usePlugIn : Boolean;
-       BoardPath : String;
-       server : String;
        islog : Boolean;
     urlHead: String;
+    datFileCheck: Boolean;
        {*
        FavoThreadItem : TFavoriteThreadItem;
        Node: TTreeNode;
        *}
+{$IFDEF DEBUG}
+    st, rt: Cardinal;
+{$ENDIF}
 begin
+{$IFDEF DEBUG}
+       st := GetTickCount;
+{$ENDIF}
        if Board.IsThreadDatRead then
                Exit;
        Board.Clear;
        UnRead := 0;
        usePlugIn := Board.IsBoardPlugInAvailable;
-       server :=  UrlToServer( Board.URL );
+       //server :=  UrlToServer( Board.URL );
+    // \83X\83\8c\83b\83h\82Å\8b¤\92Ê\82ÌURL\95\94
+    if Board.is2ch then begin
+        urlHead := UrlToServer( Board.URL ) + 'test/read.cgi/' + Board.BBSID + '/';
+    end else begin
+        urlHead := UrlToServer( Board.URL ) + 'test/read.cgi?bbs=' + Board.BBSID + '&key=';
+    end;
 
        FileName := Board.GetFolderIndexFileName;
 
-       FileList := TStringList.Create;
-       FileList.Sorted := True;
-       FileList.BeginUpdate;
-       //IsLogFile\97pDAT\83t\83@\83C\83\8b\83\8a\83X\83g
-       GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.dat', FileList, False);
-       FileList.EndUpdate;
+    //
+    datFileCheck := (Setting.CheckDatFile) or (not FileExists(FileName));
+    if (datFileCheck) then begin
+        FileList := TStringList.Create;
+        FileList.Sorted := True;
+        FileList.BeginUpdate;
+        //IsLogFile\97pDAT\83t\83@\83C\83\8b\83\8a\83X\83g
+        GetFileList(ExtractFileDir(Board.GetFolderIndexFileName), '*.dat', FileList, False);
+        FileList.EndUpdate;
+    end;
 
        // \8fd\95¡\82ð\96h\82®
        Board.BeginUpdate;
        Board.Sorted := True;
-
        sl := TStringList.Create;
        try
                if FileExists(FileName) then begin
                        sl.LoadFromFile(FileName);
-            // \83X\83\8c\83b\83h\82Å\8b¤\92Ê\82ÌURL\95\94
-            if Board.is2ch then begin
-                urlHead := server + 'test/read.cgi/' + Board.BBSID + '/';
-            end else begin
-                urlHead := server + 'test/read.cgi?bbs=' + Board.BBSID + '&key=';
-            end;
                        //\82Q\8ds\96Ú\82©\82ç\81i\82P\8ds\96Ú\82Í\83o\81[\83W\83\87\83\93\81j
                        for i := sl.Count - 1 downto 1 do begin
                                Rec := ParseIndexLine(sl[i]);
-                               islog := FileList.Find( Rec.FFileName, Index );
+                if (datFileCheck) then begin
+                               islog := FileList.Find( Rec.FFileName, Index );
+                end else begin
+                    islog := (Rec.FSize <> 0) and (Rec.FCount <> 0);
+                end;
                                if usePlugIn then
                                        ThreadItem := TThreadItem.Create(
                                                        Board.BoardPlugIn,
@@ -635,8 +667,8 @@ begin
                                        end;
                                end;
 
-                               ThreadItem.BeginUpdate;
-                               if islog then
+                               //ThreadItem.BeginUpdate;
+                               if (datFileCheck) and (islog) then
                                        FileList.Delete( Index );
 
                                ThreadItem.No := Rec.FNo;
@@ -660,10 +692,10 @@ begin
                                Node := FavoriteDM.TreeView.Items.AddChildObject( FavoriteDM.TreeView.Items.Item[0], ThreadItem.Title, FavoThreadItem);
                                *}
 
-                               ThreadItem.EndUpdate;
+                               //ThreadItem.EndUpdate;
                                Board.Add(ThreadItem);
 
-                               if (ThreadItem.IsLogFile) and (ThreadItem.UnRead) then
+                               if (ThreadItem.UnRead) and (ThreadItem.IsLogFile) then
                                        Inc(UnRead);
                        end;
                end;
@@ -671,60 +703,101 @@ begin
                if UnRead <> Board.UnRead then
                        Board.UnRead := UnRead;
 
-               Boardpath := ExtractFilePath(Board.GetFolderIndexFileName);
-               //\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
-               for i := 0 to FileList.Count - 1 do begin
-                       FileName := Boardpath + FileList[i];
-
-                       //ResRec := DivideStrLine(ReadThreadFile(FileName, 1));
-                       if usePlugIn then begin
-                               ThreadItem := TThreadItem.Create(
-                                       Board.BoardPlugIn,
-                                       Board,
-                                       Board.BoardPlugIn.FileName2ThreadURL( DWORD( Board ), FileList[i] ) );
-                               THTMLCreate.DivideStrLine(Board.BoardPlugIn.GetDat( DWORD( ThreadItem ), 1 ), @ResRec);
-                       end else begin
-                               ThreadItem := TThreadItem.Create(
-                                       nil,
-                                       Board,
-                                       Get2chBoard2ThreadURL( Board, ChangeFileExt( FileList[i], '' ) ) );
-                               THTMLCreate.DivideStrLine(ReadThreadFile(FileName, 1), @ResRec);
-                       end;
-
-                       ThreadItem.BeginUpdate;
-                       ThreadItem.FileName := FileList[i];
-                       //ThreadItem.FilePath := FileName;
-                       ThreadItem.No := Board.Count + 1;
-                       ThreadItem.Title := ResRec.FTitle;
-                       ThreadItem.Count := GetFileLineCount(FileName);
-                       ThreadItem.AllResCount := ThreadItem.Count;
-                       ThreadItem.NewResCount := ThreadItem.Count;
-                       ThreadItem.Size := GetFileSize(FileName) - ThreadItem.Count;//1byte\82¸\82ê\82é\82Æ\82«\82ª\82 \82é\82¯\82Ç\82»\82ê\82Í\82 \82«\82ç\82ß\82é
-                       ThreadItem.RoundDate := FileDateToDateTime( FileAge( FileName ) );
-                       ThreadItem.LastModified := ThreadItem.RoundDate;
-                       ThreadItem.Kokomade := -1;
-                       ThreadItem.NewReceive := 0;
-                       ThreadItem.ParentBoard := Board;
-                       ThreadItem.IsLogFile := True;
-                       ThreadItem.Round := False;
-                       ThreadItem.UnRead := False;
-                       ThreadItem.ScrollTop := 0;
-                       ThreadItem.AgeSage := gasNone;
-                       ThreadItem.EndUpdate;
-                       Board.Add(ThreadItem);
-               end;
+        if (datFileCheck) then begin
+                   //\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
+            AddOutofIndexDat(Board, FileList);
+        end;
                Board.EndUpdate;
-        
+
         //\91O\89ñ\88Ù\8fí\8fI\97¹\8e\9e\83`\83F\83b\83N
         RestoreThreadData( Board );
        finally
                sl.Free;
-               FileList.Free;
+        if (datFileCheck) then begin
+               FileList.Free;
+        end;
                Board.Sorted := False;
        end;
        Board.IsThreadDatRead := True;
+{$IFDEF DEBUG}
+       rt := GetTickCount - st;
+       Writeln('Read Done.' + Board.Title + ':' + IntToStr(rt) + ' ms');
+{$ENDIF}
 end;
+{!
+\brief \83C\83\93\83f\83b\83N\83X\82É\82È\82¢dat\81i\82Í\82®\82êdat\81j\82Ì\92Ç\89Á
+\param Board \92Ç\89Á\82·\82é\94Â
+\param DatList  dat\83t\83@\83C\83\8b\96¼
+}
+procedure TGikoSys.AddOutofIndexDat(Board: TBoard; DatList: TStringList; AllCreate: Boolean = True);
+var
+    i : Integer;
+    Boardpath,FileName : String;
+    ResRec: TResRec;
+    ThreadItem: TThreadItem;
+    create: Boolean;
+begin
+    create := False;
+    Boardpath := ExtractFilePath(Board.GetFolderIndexFileName);
+    //\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
+    for i := 0 to DatList.Count - 1 do begin
+        FileName := Boardpath + DatList[i];
+        ThreadItem := nil;
+        if (not AllCreate) then begin
+            create := False;
+            ThreadItem := Board.FindThreadFromFileName(DatList[i]);
+            if (ThreadItem = nil) then begin
+                create := True;
+            end else begin
+                if Board.IsBoardPlugInAvailable then begin
+                    THTMLCreate.DivideStrLine(Board.BoardPlugIn.GetDat( DWORD( ThreadItem ), 1 ), @ResRec);
+                end else begin
+                    THTMLCreate.DivideStrLine(ReadThreadFile(FileName, 1), @ResRec);
+                end;
+            end;
+        end;
+        if (ThreadItem = nil) then begin
+            if Board.IsBoardPlugInAvailable then begin
+                ThreadItem := TThreadItem.Create(
+                    Board.BoardPlugIn,
+                    Board,
+                    Board.BoardPlugIn.FileName2ThreadURL( DWORD( Board ), DatList[i] ) );
+                THTMLCreate.DivideStrLine(Board.BoardPlugIn.GetDat( DWORD( ThreadItem ), 1 ), @ResRec);
+            end else begin
+                ThreadItem := TThreadItem.Create(
+                    nil,
+                    Board,
+                    Get2chBoard2ThreadURL( Board, ChangeFileExt( DatList[i], '' ) ) );
+                THTMLCreate.DivideStrLine(ReadThreadFile(FileName, 1), @ResRec);
+            end;
+        end;
+        
 
+        ThreadItem.BeginUpdate;
+        ThreadItem.FileName := DatList[i];
+        //ThreadItem.FilePath := FileName;
+        ThreadItem.No := Board.Count + 1;
+        ThreadItem.Title := ResRec.FTitle;
+        ThreadItem.Count := GetFileLineCount(FileName);
+        ThreadItem.AllResCount := ThreadItem.Count;
+        ThreadItem.NewResCount := ThreadItem.Count;
+        ThreadItem.Size := GetFileSize(FileName) - ThreadItem.Count;//1byte\82¸\82ê\82é\82Æ\82«\82ª\82 \82é\82¯\82Ç\82»\82ê\82Í\82 \82«\82ç\82ß\82é
+        ThreadItem.RoundDate := FileDateToDateTime( FileAge( FileName ) );
+        ThreadItem.LastModified := ThreadItem.RoundDate;
+        ThreadItem.Kokomade := -1;
+        ThreadItem.NewReceive := 0;
+        ThreadItem.ParentBoard := Board;
+        ThreadItem.IsLogFile := True;
+        ThreadItem.Round := False;
+        ThreadItem.UnRead := False;
+        ThreadItem.ScrollTop := 0;
+        ThreadItem.AgeSage := gasNone;
+        ThreadItem.EndUpdate;
+        if (AllCreate) or (create) then begin
+            Board.Add(ThreadItem);
+        end;
+    end;
+end;
 {!
 \brief \83X\83\8c\83b\83h\83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b(Folder.idx)\8dì\90¬
 \param Board Folder.idx \82ð\8dì\90¬\82·\82é\94Â
@@ -883,21 +956,21 @@ end;
 }
 function TGikoSys.ParseIndexLine(Line: string): TIndexRec;
 begin
-       Result.FNo := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       Result.FFileName := RemoveToken(Line, #1);
-       Result.FTitle := MojuUtils.UnSanitize(RemoveToken(Line, #1));
-       Result.FCount := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       Result.FSize := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       Result.FRoundDate := IntToDateTime(StrToIntDef('$' + RemoveToken(Line, #1), ZERO_DATE));
-       Result.FLastModified := IntToDateTime(StrToIntDef('$' + RemoveToken(Line, #1), ZERO_DATE));
-       Result.FKokomade := StrToIntDef('$' + RemoveToken(Line, #1), -1);
-       Result.FNewReceive := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       RemoveToken(Line, #1);//9: ;    //\96¢\8eg\97p
-       Result.FUnRead := IntToBool(StrToIntDef('$' + RemoveToken(Line, #1), 0));
-       Result.FScrollTop := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       Result.FAllResCount := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       Result.FNewResCount := StrToIntDef('$' + RemoveToken(Line, #1), 0);
-       Result.FAgeSage := TGikoAgeSage(StrToIntDef('$' + RemoveToken(Line, #1), 0));
+       Result.FNo := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       Result.FFileName := MojuUtils.RemoveToken(Line, #1);
+       Result.FTitle := MojuUtils.UnSanitize(MojuUtils.RemoveToken(Line, #1));
+       Result.FCount := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       Result.FSize := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       Result.FRoundDate := IntToDateTime(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), ZERO_DATE));
+       Result.FLastModified := IntToDateTime(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), ZERO_DATE));
+       Result.FKokomade := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), -1);
+       Result.FNewReceive := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       MojuUtils.RemoveToken(Line, #1);//9: ;  //\96¢\8eg\97p
+       Result.FUnRead := IntToBool(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0));
+       Result.FScrollTop := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       Result.FAllResCount := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       Result.FNewResCount := StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0);
+       Result.FAgeSage := TGikoAgeSage(StrToIntDef('$' + MojuUtils.RemoveToken(Line, #1), 0));
 
 end;
 
@@ -1047,8 +1120,8 @@ begin
                Delim := ','
        else
                Delim := '<>';
-       Result.FFileName := RemoveToken(Line, Delim);
-       Result.FTitle := Trim(RemoveToken(Line, Delim));
+       Result.FFileName := MojuUtils.RemoveToken(Line, Delim);
+       Result.FTitle := Trim(MojuUtils.RemoveToken(Line, Delim));
 
        ws := Result.FTitle;
        if Copy(ws, Length(ws), 1) = ')' then begin
@@ -1135,10 +1208,10 @@ end;
 }
 function TGikoSys.DirectoryExistsEx(const Name: string): Boolean;
 var
-       Code: Integer;
+       Code: Cardinal;
 begin
        Code := GetFileAttributes(PChar(Name));
-       Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
+       Result := (Code <> Cardinal(-1)) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
 end;
 
 {!
@@ -1293,17 +1366,15 @@ var
        nm: NONCLIENTMETRICS;
 begin
        nm.cbSize := sizeof(NONCLIENTMETRICS);
-
-       SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @nm, 0);
-       lf := nm.lfMenuFont;
-
-       Font.Name := lf.lfFaceName;
-       Font.Height := lf.lfHeight;
-       Font.Style := [];
-       if lf.lfWeight >= 700 then
-               Font.Style := Font.Style + [fsBold];
-       if lf.lfItalic = 1 then
-               Font.Style := Font.Style + [fsItalic];
+    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @nm, 0);
+    lf := nm.lfMenuFont;
+    Font.Name := lf.lfFaceName;
+    Font.Height := lf.lfHeight;
+    Font.Style := [];
+    if lf.lfWeight >= 700 then
+        Font.Style := Font.Style + [fsBold];
+    if lf.lfItalic = 1 then
+        Font.Style := Font.Style + [fsItalic];
 end;
 
 {!
@@ -1314,7 +1385,7 @@ end;
 
 \82Ç\82±\82©\82Ì\83T\83C\83g\82©\82ç\82Ì\83p\83N\83\8a
 }
-function TGikoSys.RemoveToken(var s: string;const delimiter: string): string;
+{function TGikoSys.RemoveToken(var s: string;const delimiter: string): string;
 var
        p: Integer;
 begin
@@ -1325,7 +1396,7 @@ begin
                Result := Copy(s, 1, p - 1);
        Delete(s, 1, Length(Result) + Length(delimiter));
 end;
-
+}
 
 {!
 \brief n \8cÂ\96Ú\82Ì\83g\81[\83N\83\93\82ð\90Ø\82è\8fo\82µ
@@ -1341,7 +1412,7 @@ var
 begin
        Result := '';
        for i := 0 to index do
-               Result := RemoveToken(s, delimiter);
+               Result := MojuUtils.RemoveToken(s, delimiter);
 end;
 
 
@@ -1376,7 +1447,7 @@ var
        S : string;
        i : integer;
 begin
-       s := Trim(LongName);
+    s := TrimThreadTitle(Trim(LongName));
        if (Length(s) <= ALength) then begin
                Result := s;
        end else begin
@@ -1409,6 +1480,33 @@ begin
        end;
 end;
 
+function TGikoSys.TrimThreadTitle(const SrcTitle: string): string;
+const
+    TRIM_STRING: array [1..4] of String =
+        ('[\93]\8dÚ\8bÖ\8e~]', '&copy;2ch.net', '&copy;bbspink.com', #9);
+var
+    i: Integer;
+    Idx: Integer;
+    Len: Integer;
+    DstTitle: String;
+begin
+    if (Setting.ThreadTitleTrim = True) then begin
+        DstTitle := SrcTitle;
+               for i := Low(TRIM_STRING) to High(TRIM_STRING) do begin
+            Len := Length(TRIM_STRING[i]);
+            while (True) do begin
+                Idx := Pos(TRIM_STRING[i], DstTitle);
+                if (Idx < 1) then
+                    Break;
+                Delete(DstTitle, Idx, Len);
+            end;
+        end;
+        Result := Trim(DstTitle);
+    end else begin
+        Result := SrcTitle;
+    end;
+end;
+
 {!
 \brief Boolean \82ð Integer \82É\95Ï\8a·
 \return False..0, True..1
@@ -1583,7 +1681,7 @@ begin
        SI.cbReserved2 := 0;
        SI.lpReserved2 := nil;
        SI.dwysize               := 0;
-       Windows.CreateProcess(nil,
+    if Windows.CreateProcess(nil,
                                                                PChar(Path),
                                                                nil,
                                                                nil,
@@ -1592,7 +1690,11 @@ begin
                                                                nil,
                                                                nil,
                                                                SI,
-                                                               PI);
+                                                               PI) then
+    begin
+        CloseHandle(PI.hProcess);
+    end;
+
 end;
 
 {!
@@ -1601,14 +1703,45 @@ end;
 \param BrowserType \83u\83\89\83E\83U\82Ì\83^\83C\83v(IE \82©\82Ç\82¤\82©)
 }
 procedure TGikoSys.OpenBrowser(URL: string; BrowserType: TGikoBrowserType);
+var
+    i, j : Integer;
+    path, arg : String;
+    params : TStringList;
 begin
        case BrowserType of
                gbtIE:
                        HlinkNavigateString(nil, PWideChar(WideString(URL)));
                gbtUserApp, gbtAuto:
-                       if (Setting.URLApp) and (FileExists(Setting.URLAppFile)) then
-                               GikoSys.CreateProcess(Setting.URLAppFile, URL)
-                       else
+                       if (Setting.URLApp) then begin
+                if (FileExists(Setting.URLAppFile)) then begin
+                               GikoSys.CreateProcess(Setting.URLAppFile, URL)
+                end else begin
+                    // \8bN\93®\83p\83\89\83\81\81[\83^\95t\82«\91Î\8dô
+                    path := '';
+                    params := TStringList.Create;
+                    try
+                        params.Delimiter := ' ';
+                        params.DelimitedText := Setting.URLAppFile;
+                        for i := 0 to params.Count - 1 do begin
+                            path := TrimLeft(path + ' ' + params[i]);
+                            if (FileExists(path)) then begin
+                                arg := '';
+                                for j := i + 1 to params.Count - 1 do begin
+                                    arg := arg + ' ' + params[j];
+                                end;
+                                break;
+                            end;
+                        end;
+                        if i < params.Count then begin
+                            GikoSys.CreateProcess(path, arg + ' ' + URL);
+                        end else begin
+                            HlinkNavigateString(nil, PWideChar(WideString(URL)));
+                        end;
+                    finally
+                        params.Free;
+                    end;
+                end;
+                       end else
                                HlinkNavigateString(nil, PWideChar(WideString(URL)));
        end;
 end;
@@ -1745,7 +1878,7 @@ end;
 }
 function TGikoSys.Is2chHost(Host: string): Boolean;
 const
-       HOST_NAME: array[0..1] of string = ('2ch.net', 'bbspink.com');
+       HOST_NAME: array[0..1] of string = ('.2ch.net', '.bbspink.com');
 var
        i: Integer;
 //     Len: Integer;
@@ -1786,7 +1919,13 @@ begin
        Index := AnsiPos(READ_PATH, path);
        if Index <> 0 then begin
                s := Copy(path, Index + Length(READ_PATH), Length(path));
-
+    end else begin
+        Index := AnsiPos(HTML_READ_PATH, path);
+        if Index <> 0 then begin
+            s := Copy(path, Index + Length(HTML_READ_PATH), Length(path));
+        end;
+    end;
+    if Index <> 0 then begin
                if (Length(s) > 0) and (s[1] = '/') then
                        Delete(s, 1, 1);
                BBSID := GetTokenIndex(s, '/', 0);
@@ -1836,84 +1975,93 @@ http://2ch.net/
 \82Ì\8fê\8d\87 stRef = 32, endRes = 50 \82É\82È\82é
 }
 procedure TGikoSys.GetPopupResNumber(URL : string; var stRes, endRes : Int64);
+const
+    START_NAME : array[0..1] of String = ('st=', 'start=');
+    END_NAME : array[0..1] of String = ('to=', 'end=');
+    RES_NAME : array[0..0] of String = ('res=');
 var
        buf : String;
        convBuf : String;
        ps : Int64;
        pch : PChar;
+    bufList : TStringList;
+    i, j, idx : Integer;
 begin
        URL := Trim(LowerCase(URL));
-       if (AnsiPos('&st=', URL ) <> 0) and ( AnsiPos( '&to=',URL) <> 0 ) then begin
-               stRes := 0;
-               endRes := 0;
-               try
-                       buf := Copy( URL, AnsiPos('&st=', URL ) + 4, AnsiPos( '&to=',URL) - AnsiPos('&st=', URL ) - 4 );
-                       if buf <> '' then
-                               stRes := StrToInt64( buf );
-                       if AnsiPos( '&nofirst=',URL) <> 0 then begin
-                               buf := Copy( URL, AnsiPos('&to=', URL ) + 4, AnsiPos( '&nofirst=',URL) - AnsiPos('&to=', URL ) - 4);
-                       end else begin
-                               buf := Copy( URL, AnsiPos('&to=', URL ) + 4, Length( URL ) - AnsiPos('&to=', URL ) - 4 + 1 );
-                               ps := 0;
-                               pch := PChar(buf);
-                               while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
-                               buf := Copy( buf, 1, ps );
-                       end;
-                       try
-                               if buf <> '' then
-                                       endRes := StrToInt64(buf)
-                       except
-                               endRes := 0;
-                       end;
-               except
-                       stRes := 0;
-               end;
-               if (stRes <> 0) and (endRes = 0) then
-                       endRes := stRes + MAX_POPUP_RES
-               else if (stRes = 0) and (endRes <> 0) then begin
-                       stRes := endRes - MAX_POPUP_RES;
-                       if stRes < 1 then
-                               stRes := 1;
-               end;
-               GikoSys.GetBrowsableThreadURL( URL );
-       end else if( AnsiPos('&res=', URL ) <> 0 ) then begin
-               endRes := 0;
-               buf := Copy( URL, AnsiPos('&res=', URL ) + 5, Length( URL ) - AnsiPos('&res=', URL ) - 5 + 1 );
-               ps := 0;
-               pch := PChar(buf);
-               while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
-               buf := Copy( buf, 1, ps );
-               try
-                       if buf <> '' then
-                               stRes := StrToInt(buf)
-                       else begin
-                               stRes := 0;
-                       end;
-               except
-                       stRes := 0;
-               end;
-       end else if (AnsiPos('&start=', URL ) <> 0) and ( AnsiPos( '&end=',URL) <> 0 ) then begin
-               try
-                       stRes := StrToInt64( Copy( URL, AnsiPos('&start=', URL ) + 7, AnsiPos( '&end=',URL) - AnsiPos('&start=', URL ) - 7 ) );
-                       if AnsiPos( '&nofirst=',URL) <> 0 then begin
-                               buf := Copy( URL, AnsiPos('&end=', URL ) + 5, AnsiPos( '&nofirst=',URL) - AnsiPos('&end=', URL ) - 5);
-                       end else begin
-                               buf := Copy( URL, AnsiPos('&end=', URL ) + 5, Length( URL ) - AnsiPos('&to=', URL ) - 5 + 1 );
-                               ps := 0;
-                               pch := PChar(buf);
-                               while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
-                               buf := Copy( buf, 1, ps );
-                       end;
-                       try
-                               if buf <> '' then
-                                       endRes := StrToInt64(buf);
-                       except
-                               endRes := 0;
-                       end;
-               except
-                       stRes := 0;
-               end;
-       end else if ( AnsiPos('.html',URL) <> Length(URL) -4 ) and ( AnsiPos('.htm',URL) <> Length(URL) -3 ) then begin
+    for i := 0 to Length(START_NAME) -1 do begin
+        idx := AnsiPos(START_NAME[i], URL);
+        if (idx <> 0) then begin
+            break;
+        end;
+        idx := AnsiPos(END_NAME[i], URL);
+        if (idx <> 0) then begin
+            break;
+        end;
+
+    end;
+
+    if (idx <> 0) then begin
+        idx := AnsiPos('?', URL);
+        if (idx = 0) then begin
+            idx := LastDelimiter('/', URL);
+        end;
+        stRes := 0;
+        endRes := 0;
+        bufList := TStringList.Create();
+        try
+            bufList.Delimiter := '&';
+            bufList.DelimitedText := Copy(URL, idx + 1, Length(URL));
+            for  i := 0 to bufList.Count - 1 do begin
+                convBuf := '';
+                // \8aJ\8en\83\8c\83X\94Ô\82Ì\8c\9f\8dõ
+                if (stRes = 0) then begin
+                    for j := 0 to Length(START_NAME) - 1 do begin
+                        idx := AnsiPos(START_NAME[j], bufList[i]);
+                        if (idx = 1) then begin
+                            convBuf := Copy(bufList[i], idx + Length(START_NAME[j]), Length(bufList[i]));
+                            stRes := StrToInt64Def( convBuf, 0 );
+                            break;
+                        end;
+                    end;
+                end;
+                // \8fI\97¹\83\8c\83X\94Ô\82Ì\8c\9f\8dõ
+                if (convBuf = '') and (endRes = 0) then begin
+                    for j := 0 to Length(END_NAME) - 1 do begin
+                        idx := AnsiPos(END_NAME[j], bufList[i]);
+                        if (idx = 1) then begin
+                            convBuf := Copy(bufList[i], idx + Length(END_NAME[j]), Length(bufList[i]));
+                            endRes := StrToInt64Def( convBuf, 0 );
+                            break;
+                        end;
+                    end;
+                end;
+                // \83\8c\83X\94Ô\82Ì\8c\9f\8dõ
+                if ((stRes = 0) and (endRes = 0) and (convBuf = '')) then begin
+                  for j := 0 to Length(RES_NAME) - 1 do begin
+                      idx := AnsiPos(RES_NAME[j], bufList[i]);
+                      if (idx = 1) then begin
+                          convBuf := Copy(bufList[i], idx + Length(RES_NAME[j]), Length(bufList[i]));
+                          stRes := StrToInt64Def( convBuf, 0 );
+                          endRes := stRes;
+                          break;
+                      end;
+                  end;
+                end;
+            end;
+
+            if (stRes <> 0) and (endRes = 0) then begin
+                       endRes := stRes + MAX_POPUP_RES;
+               end else if (stRes = 0) and (endRes <> 0) then begin
+                stRes := endRes - MAX_POPUP_RES;
+                       if stRes < 1 then begin
+                               stRes := 1;
+                end;
+            end;
+        finally
+            bufList.clear;
+            bufList.free;
+        end;
+    end else if ( AnsiPos('.html',URL) <> Length(URL) -4 ) and ( AnsiPos('.htm',URL) <> Length(URL) -3 ) then begin
                buf := Copy(URL, LastDelimiter('/',URL)+1,Length(URL)-LastDelimiter('/',URL)+1);
                if  Length(buf) > 0 then begin
                        if AnsiPos('-', buf) = 1 then begin
@@ -1922,15 +2070,10 @@ begin
                                ps := 0;
                                pch := PChar(buf);
                                while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
-                               try
-                                       convBuf := Copy( buf, 1, ps );
-                                       if convBuf <> '' then
-                                               endRes := StrToInt64(convBuf)
-                                       else
-                                               endRes := 0;
-                               except
-                                       endRes := 0;
-                               end;
+                convBuf := Copy( buf, 1, ps );
+                if convBuf <> '' then begin
+                    endRes := StrToInt64Def(convBuf, 0);
+                end;
                                if endRes <> 0 then begin
                                        stRes := endRes - MAX_POPUP_RES;
                                        if stRes < 1 then
@@ -1948,15 +2091,10 @@ begin
                                                ps := 0;
                                                pch := PChar(buf);
                                                while  ( ps < Length(buf) )and ( pch[ps] >= '0' ) and ( pch[ps] <= '9' ) do Inc(ps);
-                                               try
-                                                       convBuf := Copy( buf, 1, ps );
-                                                       if convBuf <> '' then
-                                                               endRes := StrToInt64(convBuf)
-                                                       else
-                                                               endRes := 0;
-                                               except
-                                                       endRes := 0;
-                                               end;
+                        convBuf := Copy( buf, 1, ps );
+                        if convBuf <> '' then begin
+                            endRes := StrToInt64Def(convBuf, 0);
+                        end;
                                        end else begin
                                                stRes := 0;
                                        end;
@@ -1966,9 +2104,6 @@ begin
                                end;
                        end;
                end;
-       end else begin
-               //stRes := 0;
-               //endRes := 0;
        end;
 end;
 
@@ -2015,7 +2150,7 @@ begin
                //\95W\8f\80\8f\91\8e®
                //\8dÅ\8cã\82Íl50, 10, 10-20, 10n, 10-20n, -10, 10-, 10n- \82È\82Ç
                //http://xxx.2ch.net/test/read.cgi/bbsid/1000000000/
-               FAWKStr.RegExp := '/test/read.cgi/.+/[0-9]+/?.*';
+               FAWKStr.RegExp := '/test/read.(cgi|html)/.+/[0-9]+/?.*';
                if FAWKStr.Match(FAWKStr.ProcessEscSeq(s), RStart, RLength) > 0 then begin
                        s := Copy(s, 15, Length(s));
 
@@ -2453,6 +2588,7 @@ procedure TGikoSys.ListBoardFile;
 var
        boardFileList   : TStringList;
        i, l                    : Integer;
+    sCategory       : TCategory;
 begin
        // BBS \82Ì\8aJ\95ú
        try
@@ -2495,6 +2631,20 @@ begin
                BoardFileList.Free;
          end;
        end;
+
+    // \93Á\8eê\97p\93rBBS\90\90¬
+    // \8aù\82É\91\8dÝ\82·\82é\8fê\8d\87\82Í\8dí\8f\9c\82·\82é
+    DestorySpecialBBS(BoardGroup.SpecialBBS);
+    SpecialBBS := TBBS.Create('');
+    SpecialBBS.Title := '\93Á\8eê\97p\93r(\94ñ\95\\8e¦)';
+    sCategory := TCategory.Create;
+    sCategory.No := 1;
+    sCategory.Title := '\93Á\8eê\97p\93r(\94ñ\95\\8e¦)';
+    SpecialBBS.Add(sCategory);
+    BoardGroup.SpecialBoard := TSpecialBoard.Create(nil, 'http://localhost/gikonavi/special/index.html');
+    BoardGroup.SpecialBoard.Title := '\83^\83u\88ê\97\97';
+    BoardGroup.SpecialBoard.IsThreadDatRead := True;
+    sCategory.Add(BoardGroup.SpecialBoard);
 end;
 
 {!
@@ -2692,19 +2842,18 @@ function TGikoSys.GetSambaFileName : string;
 begin
        Result := Setting.GetSambaFileName;
 end;
-
 {!
-\brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\83A\83\93\83J\81[\82É\82µ\82Ä\97ñ\8b\93
-\param AID        \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
+\brief \97ñ\8b\93\82³\82ê\82½\83\8c\83X\94Ô\8d\86\82Ö\82Ì\83A\83\93\83J\81[\97pHTML\8dì\90¬
+\param Numbers    \97ñ\8b\93\82³\82ê\82½\83\8c\83X\94Ô\8d\86
 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
-\param limited    \97ñ\8b\93\82·\82é\90\94\82ð\90§\8cÀ\82·\82é\82È\82ç True
+\param limited    \97ñ\8b\93\82·\82é\90\94\82ð\90§\8cÀ\82·\82é\82È\82ç1\88È\8fã
 \return           \97ñ\8b\93\82³\82ê\82½\83\8c\83X\83A\83\93\83J\81[
-\todo limited \82ð Integer \82É\82·\82é\82©\81A20 \82ð\8aO\82É\8fo\82·
 }
-function TGikoSys.GetSameIDResAnchor(const AID : string; ThreadItem: TThreadItem; limited: boolean):string;
+function TGikoSys.CreateResAnchor(
+    var Numbers: TStringList; ThreadItem: TThreadItem;
+    limited: Integer):string;
 var
        i: integer;
-       body: TStringList;
     Res: TResRec;
     ResLink : TResLinkRec;
 begin
@@ -2712,29 +2861,22 @@ begin
     Res.FBody := '';
     Res.FType := glt2chNew;
 
-               Result := '';
-               if (not IsNoValidID(AID)) and
-                       (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
-                               body := TStringList.Create;
-                               try
-                                               GetSameIDRes(AID, ThreadItem, body);
-                                               if (limited) and (body.Count > 20) then begin
-                                                               for i := body.Count - 20 to body.Count - 1 do begin
-                                                                               Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
-                                                               end;
-                                               end else begin
-                                                               for i := 0 to body.Count - 1 do begin
-                                                                               Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
-                                                               end;
-                                               end;
-                               finally
-                                               body.Free;
-                               end;
+       Result := '';
+       if (Numbers <> nil) and (Numbers.Count > 0) then begin
+        if (limited > 0) and (Numbers.Count > limited) then begin
+            for i := Numbers.Count - limited to Numbers.Count - 1 do begin
+                Res.FBody := Res.FBody + '&gt;' + Numbers[i] + ' ';
+            end;
+        end else begin
+            for i := 0 to Numbers.Count - 1 do begin
+                Res.FBody := Res.FBody + '&gt;' + Numbers[i] + ' ';
+            end;
+        end;
         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
         ResLink.FKey := ChangeFileExt(ThreadItem.FileName, '');
         HTMLCreater.ConvRes(@Res, @ResLink, false);
         Result := Res.FBody;
-               end;
+    end;
 end;
 
 {!
@@ -2749,6 +2891,22 @@ var
        ReadList: TStringList;
        Res: TResRec;
        boardPlugIn : TBoardPlugIn;
+
+    procedure CheckSameID(const AID:String; const Target: String; no: Integer);
+    var
+        pos: Integer;
+    begin
+        pos := AnsiPos('id:', LowerCase(Target));
+        if (pos > 0) then begin
+            if(AnsiPos(AID, Copy(Target, pos-1, Length(Target))) > 0) then begin
+                body.Add(IntToStr(no));
+            end;
+        end else begin
+            if(AnsiPos(AID, Target) > 0) then begin
+                body.Add(IntToStr(no));
+            end;
+        end;
+    end;
 begin
        if (not IsNoValidID(AID)) and
        (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
@@ -2761,9 +2919,7 @@ begin
                        for i := 0 to threadItem.Count - 1 do begin
                                // \83\8c\83X
                                THTMLCreate.DivideStrLine(boardPlugIn.GetDat(DWORD( threadItem ), i + 1), @Res);
-                               if(AnsiPos(AID, Res.FDateTime) > 0) then begin
-                                       body.Add(IntToStr(i+1));
-                               end;
+                CheckSameID(AID, Res.FDateTime, i+1);
                        end;
                end else begin
                        ReadList := TStringList.Create;
@@ -2771,9 +2927,7 @@ begin
                                ReadList.LoadFromFile(ThreadItem.GetThreadFileName);
                                for i := 0 to ReadList.Count - 1 do begin
                                        THTMLCreate.DivideStrLine(ReadList[i], @Res);
-                                       if AnsiPos(AID, Res.FDateTime) > 0 then begin
-                                               body.Add(IntToStr(i+1));
-                                       end;
+                    CheckSameID(AID, Res.FDateTime, i+1);
                                end;
                        finally
                                ReadList.Free;
@@ -2786,59 +2940,29 @@ end;
 \brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\97ñ\8b\93
 \param AIDNum     \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
 \param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
-\param limited    \97ñ\8b\93\82·\82é\90\94\82ð\90§\8cÀ\82·\82é\82È\82ç True
-\return
-\todo limited \82ð Integer \82É\82·\82é\82©\81A20 \82ð\8aO\82É\8fo\82·
+\param body       OUT:\97ñ\8b\93\82³\82ê\82½\83\8c\83X\94Ô\8d\86\82ª\95Ô\82é
 }
-function TGikoSys.GetSameIDResAnchor(AIDNum : Integer; ThreadItem: TThreadItem; limited: boolean):string;
+procedure TGikoSys.GetSameIDRes(AIDNum : Integer; ThreadItem: TThreadItem;var body: TStringList);
 var
-       i: integer;
-       body: TStringList;
-    Res: TResRec;
-    ResLink : TResLinkRec;
+       AID : String;
 begin
-    // body\88È\8aO\82Í\8eg\97p\82µ\82È\82¢\82Ì\82Å\8f\89\8aú\89»\82µ\82È\82¢
-    Res.FBody := '';
-    Res.FType := glt2chNew;
-
-       Result := '';
-       if (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
-               body := TStringList.Create;
-               try
-                       GetSameIDRes(AIDNum, ThreadItem, body);
-            if (limited) and (body.Count > 20) then begin
-                       for i := body.Count - 20 to body.Count - 1 do begin
-                               Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
-                       end;
-            end else begin
-                       for i := 0 to body.Count - 1 do begin
-                               Res.FBody := Res.FBody + '&gt;' + body[i] + ' ';
-                       end;
-            end;
-               finally
-                       body.Free;
-               end;
-        ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
-        ResLink.FKey := ChangeFileExt(ThreadItem.FileName, '');
-        HTMLCreater.ConvRes(@Res, @ResLink, false);
-        Result := Res.FBody;
+    AID := GetResID(AIDNum, ThreadItem);
+    if not IsNoValidID(AID) then begin
+           GetSameIDRes(AID, ThreadItem, body);
        end;
 end;
-
 {!
-\brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\97ñ\8b\93
-\param AIDNum     \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
-\param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
-\param body       OUT:\97ñ\8b\93\82³\82ê\82½\83\8c\83X\94Ô\8d\86\82ª\95Ô\82é
+\brief \93\8a\8de ID \8eæ\93¾
+\param AIDNum     \93\8a\8d\83\8c\83X\94Ô\8d\86
+\param ThreadItem \93\8a\8de\83X\83\8c\83b\83h
+\param body       OUT:\93\8a\8deID
 }
-procedure TGikoSys.GetSameIDRes(AIDNum : Integer; ThreadItem: TThreadItem;var body: TStringList);
+function TGikoSys.GetResID(AIDNum: Integer; ThreadItem: TThreadItem): String;
 var
        Res: TResRec;
        boardPlugIn : TBoardPlugIn;
-       AID : String;
-       stList: TStringList;
-       i : Integer;
 begin
+    Result := '';
        if (ThreadItem <> nil) and (ThreadItem.IsLogFile)
                and (AIDNum > 0) and (AIDNum <= ThreadItem.Count) then begin
                //if ThreadItem.IsBoardPlugInAvailable then begin
@@ -2850,99 +2974,40 @@ begin
                end else begin
                        THTMLCreate.DivideStrLine( ReadThreadFile(ThreadItem.GetThreadFileName, AIDNum), @Res);
                end;
-               AID := Res.FDateTime;
-               if AnsiPos('id', AnsiLowerCase(AID)) > 0 then begin
-                       AID := Copy(AID, AnsiPos('id', AnsiLowerCase(AID)) - 1, 11);
-            if AnsiPos(' be:', AnsiLowerCase(AID)) > 0 then begin
-               AID := Copy(AID, 1, AnsiPos(' BE:', AnsiLowerCase(AID)) - 1)
-            end;
-               end else begin
-                       stlist := TStringList.Create;
-                       try
-                               stList.DelimitedText := AID;
-                AID := '';
-                               for i := 0 to stList.Count - 1 do
-                                       if Length(WideString(stList[i])) = 8 then begin
-                                               if NotDateorTimeString(stList[i]) then begin
-                                                       AID := stList[i];
-                                                       break;
-                                               end;
-                                       end;
-                       finally
-                               stList.Free;
-                       end;
-               end;
-        if not IsNoValidID(AID) then
-                       GetSameIDRes(AID, ThreadItem, body);
-       end;
-end;
-
-{!
-\brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\83J\83E\83\93\83g
-\param AID        \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
-\param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
-\return           \93¯\82¶ ID \82ð\8e\9d\82Â\83\8c\83X\82Ì\90\94
-}
-function TGikoSys.GetSameIDResCount(const AID : string; ThreadItem: TThreadItem):Integer;
-var
-       body: TStringList;
-begin
-    Result := 0;
-       if (not IsNoValidID(AID))
-     and (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
-               body := TStringList.Create;
-               try
-                       GetSameIDRes(AID, ThreadItem, body);
-                       Result := body.Count;
-               finally
-                       body.Free;
-               end;
+               Result := ExtructResID(Res.FDateTime);
        end;
-
 end;
-
 {!
-\brief \93¯\82\93\8a\8de ID \82ð\8e\9d\82Â\83\8c\83X\82ð\83J\83E\83\93\83g
-\param AIDNum     \8cÂ\90l\82ð\93Á\92è\82·\82é\93\8a\8de ID
-\param ThreadItem \97ñ\8b\93\82·\82é\83X\83\8c\83b\83h
-\return           \93¯\82¶ ID \82ð\8e\9d\82Â\83\8c\83X\82Ì\90\94
+\brief \83\8c\83X\82Ì\8e\9e\8d\8f\95\94\82©\82çID\82ð\92\8a\8fo\82·\82é
+\param ADateStr \8e\9e\8d\8f\95\94\82Ì\95\8e\9a\97ñ
+\return     ID(ID\82Æ\82Ý\82È\82¹\82é\95\94\95ª\82ª\82È\82¢\82Æ\82«\82Í\8bó\95\8e\9a\97ñ)
 }
-function TGikoSys.GetSameIDResCount(AIDNum : Integer; ThreadItem: TThreadItem):Integer;
+function TGikoSys.ExtructResID(ADateStr: String): String;
 var
-       body: TStringList;
+    stlist : TStringList;
 begin
-       Result := 0;
-       if (ThreadItem <> nil) and (ThreadItem.IsLogFile) then begin
-               body := TStringList.Create;
-               try
-                       GetSameIDRes(AIDNum, ThreadItem, body);
-            Result := body.Count;
-               finally
-                       body.Free;
-               end;
-       end;
-end;
-
-{!
-\brief \8e\9e\8d\8f\82ð\8e¦\82·\95\8e\9a\97ñ\82Å\82Í\96³\82¢\82©\82Ç\82¤\82©
-\param AStr \92²\82×\82é\95\8e\9a\97ñ
-\return     \8e\9e\8d\8f\82Å\82Í\96³\82¢\82È\82ç True
-\todo \94Û\92è\8c`(Not)\82æ\82è\8dm\92è\8cn(Is)
-}
-function TGikoSys.NotDateorTimeString(const AStr : string): boolean;
-begin
-       Result := false;
-       try
-               StrToDate(AStr);
-       except
-               try
-                       StrToTime(AStr);
-                       Result := false;
-               except
-                       Result := true;
-               end;
-       end;
-
+    Result := '';
+    if AnsiPos('id', AnsiLowerCase(ADateStr)) > 0 then begin
+        Result := Copy(ADateStr, AnsiPos('id', AnsiLowerCase(ADateStr)), Length(ADateStr));
+        if AnsiPos(' ', Result) > 0 then begin
+            Result := Copy(Result, 1, AnsiPos(' ', Result) - 1);
+        end;
+        Result := ' ' + Result;
+    end else begin
+        stlist := TStringList.Create;
+        try
+            stList.Delimiter := ' ';
+            stList.DelimitedText := ADateStr;
+            // \93ú\95\8e\9e\8d\8f ID \91¼\81@\82Æ\8cÅ\92è\82Å\8dl\82¦\82é
+            if (stList.Count >= 3) then begin
+                if Length(stList[3 - 1]) >= 7 then begin
+                    Result := stList[3 - 1];
+                end;
+            end;
+        finally
+            stList.Free;
+        end;
+    end;
 end;
 
 {!
@@ -3293,7 +3358,8 @@ begin
                                        ThreadItem.NewReceive := ini.ReadInteger(SECTION, 'NewReceive', 0);
 
                                        ThreadItem.Size := ini.ReadInteger(SECTION, 'Size', 0);
-                                       if(ThreadItem.Size = 0) and (FileExists(ThreadItem.GetThreadFileName)) then begin
+                    ThreadItem.IsLogFile := FileExists(ThreadItem.GetThreadFileName);
+                                       if(ThreadItem.Size = 0) and (ThreadItem.IsLogFile) then begin
                                                try
                                                        ThreadItem.Size := GetFileSize(ThreadItem.GetThreadFileName) - ThreadItem.Count;
                                                except
@@ -3378,13 +3444,115 @@ begin
        end;
 
 end;
+//! \92u\8a·\90Ý\92è\83t\83@\83C\83\8b\8eæ\93¾
+function TGikoSys.GetReplaceFileName: String;
+begin
+    Result := Setting.GetReplaceFileName;
+end;
+//! \83v\83\8c\83r\83\85\81[\8ag\92£\82Ì\90Ý\92è\83t\83@\83C\83\8b\8eæ\93¾
+function TGikoSys.GetExtpreviewFileName: String;
+begin
+    Result := Setting.GetExtprevieFileName;
+end;
+
+//! \83t\83@\83C\83\8b\96¼\82©\82ç\82Ì\83X\83\8c\83b\83h\8dì\90¬\93ú\82Ì\8eæ\93¾
+function TGikoSys.GetCreateDateFromName(FileName: String): TDateTime;
+var
+    tmp : String;
+    unixtime: Int64;  
+begin
+    // \83\8d\83O\83t\83@\83C\83\8b\82Ì\8ag\92£\8eq\82ð\82Í\82¸\82µ\82½\82à\82Ì\82ª\83X\83\8c\8dì\90¬\93ú\8e\9e
+    tmp := ChangeFileExt(FileName, '');
+    if AnsiPos('_', tmp) <> 0 then
+        if AnsiPos('_', tmp) > 9 then
+            tmp := Copy(tmp, 1, AnsiPos('_', tmp)-1)
+        else
+            Delete(tmp, AnsiPos('_', tmp), 1);
+
+    if ( Length(tmp) = 9) and ( tmp[1] = '0' ) then
+        Insert('1', tmp, 1);
+
+    unixtime := StrToInt64Def(tmp, ZERO_DATE);
+    Result := UnixToDateTime(unixtime) + OffsetFromUTC;
+end;
+
+procedure TGikoSys.ShowRefCount(msg: String; unk: IUnknown);
+{$IFDEF DEBUG}
+var
+    count : integer;
+{$ENDIF}
+begin
+    if not Assigned(unk) then
+        Exit;
+
+{$IFDEF DEBUG}
+    try
+        unk._AddRef;
+        count := unk._Release;
+
+               Writeln(msg + ' RefCount=' + IntToStr(count));
+    except
+               Writeln(msg + ' RefCount=exception!!');
+       end;
+{$ENDIF}
+end;
+function TGikoSys.GetBoukenCookie(AURL: String): String;
+var
+       Protocol, Host, Path, Document, Port,Bookmark : String;
+begin
+    Result := '';
+    GikoSys.ParseURI(AURL, Protocol, Host, Path, Document, Port,Bookmark);
+    if ( Length(Host) > 0 ) then begin
+        Result := Setting.GetBoukenCookie(Host);
+    end;
+end;
+procedure TGikoSys.SetBoukenCookie(ACookieValue, ADomain: String);
+begin
+    if ( Length(ADomain) > 0 ) then begin
+        Setting.SetBoukenCookie(ACookieValue, ADomain);
+    end;
+end;
+//! \96`\8c¯\82Ì\8f\91Domain\88ê\97\97\8eæ\93¾
+procedure TGikoSys.GetBoukenDomain(var ADomain: TStringList);
+var
+    i : Integer;
+begin
+    ADomain.Clear;
+    for i := 0 to Setting.BoukenCookieList.Count - 1 do begin
+        ADomain.Add( Setting.BoukenCookieList.Names[i] );
+    end;
+end;
+//! \96`\8c¯\82Ì\8f\91Cookie\8dí\8f\9c
+procedure TGikoSys.DelBoukenCookie(ADomain: String);
+var
+    i : Integer;
+begin
+    for i := 0 to Setting.BoukenCookieList.Count - 1 do begin
+        if ( Setting.BoukenCookieList.Names[i] = ADomain ) then begin
+            Setting.BoukenCookieList.Delete(i);
+            Break;
+        end;
+    end;
+end;
+function TGikoSys.GetBouken(AURL: String; var Domain: String): String;
+var
+       Protocol, Host, Path, Document, Port,Bookmark : String;
+    Cookie : String;
+begin
+    Domain := '';
+    Cookie := '';
+    GikoSys.ParseURI(AURL, Protocol, Host, Path, Document, Port,Bookmark);
+    if ( Length(Host) > 0 ) then begin
+        Setting.GetBouken(Host, Domain, Cookie);
+        Result := Cookie;
+    end;
+end;
 
 initialization
        GikoSys := TGikoSys.Create;
 
 finalization
        if GikoSys <> nil then begin
-               GikoSys.Free;
-               GikoSys := nil;
+               FreeAndNil(GikoSys);
        end;
 end.