OSDN Git Service

・TThreadItem の作成時に IsLogFile が設定されるようになった。
[gikonavigoeson/gikonavi.git] / BoardGroup.pas
index 65b35ea..1db76d2 100644 (file)
@@ -3,7 +3,8 @@ unit BoardGroup;
 interface
 
 uses
-       SysUtils, Classes, ComCtrls, IniFiles, {HTTPApp,} YofUtils, IdGlobal;
+       Windows, SysUtils, Classes, ComCtrls, IniFiles, {HTTPApp,} YofUtils, IdGlobal,
+       ExternalBoardManager, ExternalBoardPlugInMain;
 
 type
        //\83\8a\83X\83g\82Ì\95\\8e¦\83A\83C\83e\83\80\91I\91ð
@@ -46,7 +47,7 @@ type
 }
 
 {
-       TBBS2ch = class(TBBS)
+       TBBS = class(TBBS)
        end;
        TBoard2ch = class(TBoard)
        end;
@@ -70,7 +71,7 @@ type
        TThreadItem = class;
 
        //\82Æ\82è\82 \82¦\82¸\82Q\82¿\82á\82ñ\82Ë\82é\82Ì\83\8b\81[\83g
-       TBBS2ch = class(TList)
+       TBBS = class(TList)
        private
                FTitle: string;
                FLogFolder: string;
@@ -86,23 +87,21 @@ type
                constructor Create(LogFolder: string);
                destructor Destroy; override;
 
-               procedure ReadBoardFile;
-
-               function GetBoardFromBBSID(BBSID: string): TBoard;
-
                function Add(item: TCategory): integer;
                procedure Delete(index: integer);
                procedure Clear; override;
                function Find(key: string): TCategory;
                function FindBBSID(BBSID: string): TBoard;
                function FindBoardFromTitle(Title: string): TBoard;
+               function FindBoardFromURL(inURL: string): TBoard;
+               function FindThreadFromURL( inURL : string ) : TThreadItem;
                function FindThreadItem(BBSID: string; FileName: string): TThreadItem;
                function GetLogFolder: string;
 
                property Items[index: integer]: TCategory read GetCategory write SetCategory;
                property Title: string read FTitle write FTitle;
                property NodeExpand: Boolean read FExpand write FExpand;
-
+                                                                                
                property KubetsuChk: Boolean read FKubetsuChk write FKubetsuChk;
                property SelectText: string read FSelectText write SetSelectText;
                property ShortSelectText: string read FShortSelectText write FShortSelectText;
@@ -113,7 +112,7 @@ type
        private
                FNo: Integer;
                FTitle: string;
-               FParentBBS2ch: TBBS2ch;
+               FParenTBBS: TBBS;
                FExpand: Boolean;
 
                function GetBoard(index: integer): TBoard;
@@ -125,7 +124,7 @@ type
                property No: Integer read FNo write FNo;
                property Title: string read FTitle write FTitle;
                property Items[index: integer]: TBoard read GetBoard write SetBoard;
-               property ParentBBS2ch: TBBS2ch read FParentBBS2ch write FParentBBS2ch;
+               property ParenTBBS: TBBS read FParenTBBS write FParenTBBS;
 
                function Add(item: TBoard): integer;
                procedure Delete(index: integer);
@@ -133,6 +132,8 @@ type
                function FindName(key: string): TBoard;
                function FindBBSID(BBSID: string): TBoard;
                function FindBoardFromTitle(Title: string): TBoard;
+               function FindBoardFromURL(inURL: string): TBoard;
+               function FindThreadFromURL( inURL : string ) : TThreadItem;
                function IsMidoku: Boolean;
 
                property NodeExpand: Boolean read FExpand write FExpand;
@@ -141,6 +142,8 @@ type
        //\94Â
        TBoard = class(TList)
        private
+               FContext: DWORD;                                        // \83v\83\89\83O\83C\83\93\82ª\8e©\97R\82É\90Ý\92è\82µ\82Ä\82¢\82¢\92l(\8eå\82É\83C\83\93\83X\83^\83\93\83X\82ª\93ü\82é)
+
                FNo: Integer;                                                                   //\94Ô\8d\86
                FTitle: string;                                                         //\83{\81[\83h\83^\83C\83g\83\8b
                FBBSID: string;                                                         //BBSID
@@ -152,7 +155,7 @@ type
                FLastGetTime: TDateTime;                        //\83X\83\8c\83b\83h\82Ü\82½\82Í\83X\83\8c\83b\83h\88ê\97\97\82ð\8dÅ\8cã\82É\8dX\90V\82µ\82½\93ú\8e\9e\81i\83T\81[\83o\91¤\93ú\8e\9e\81E\8f\91\82«\8d\9e\82Ý\8e\9e\82É\8eg\97p\82·\82é\81j
                FIsThreadDatRead: Boolean;              //\83X\83\8c\83b\83h\83\8a\83X\83g\82Í\93Ç\82Ý\8d\9e\82Ü\82ê\82Ä\82¢\82é\82©\81H
                FUnRead: Integer;                                                       //\83X\83\8c\83b\83h\96¢\93Ç\90\94
-               FParentCategory: TCategory;   //\90e\83J\83e\83S\83\8a
+               FParentCategory: TCategory;      //\90e\83J\83e\83S\83\8a
                FModified: Boolean;                                             //\8fC\90³\83t\83\89\83O
                FBoolData: Boolean;                                             //\82¢\82ë\82ñ\82È\97p\93r\82É\8eg\82¤yo
                FSPID: string;                                                          //\8f\91\82«\8d\9e\82Ý\97pSPID
@@ -163,6 +166,12 @@ type
                FUpdate: Boolean;
                FExpand: Boolean;
 
+               FBoardPlugIn    : TBoardPlugIn; // \82±\82Ì\94Â\82ð\83T\83|\81[\83g\82·\82é\83v\83\89\83O\83C\83\93
+               FFilePath                       : string;                               // \82±\82Ì\83X\83\8c\88ê\97\97\82ª\95Û\91\82³\82ê\82Ä\82¢\82é\83p\83X
+               FIsLogFile              : Boolean;                      // \83\8d\83O\91\8dÝ\83t\83\89\83O
+               FIntData                        : Integer;                      // \8dD\82«\82É\82¢\82\82Á\82Ä\82æ\82µ\81B\82¢\82ë\82ñ\82È\97p\93r\82É\8eg\82¤yo
+               FListData                       : TList;                                // \8dD\82«\82É\82¢\82\82Á\82Ä\82æ\82µ\81B\82¢\82ë\82ñ\82È\97p\93r\82É\8eg\82¤yo
+
                function GetThreadItem(index: integer): TThreadItem;
                procedure SetThreadItem(index: integer; value: TThreadItem);
                procedure SetRound(b: Boolean);
@@ -172,10 +181,13 @@ type
                procedure SetUnRead(i: Integer);
                procedure SetKotehanName(s: string);
                procedure SetKotehanMail(s: string);
+               procedure Create; overload;
        public
-               constructor Create;
+               constructor Create( inPlugIn : TBoardPlugIn; inURL : string ); overload;
                destructor Destroy; override;
 
+               property Context: DWORD read FContext write FContext;
+
                property Items[index: integer]: TThreadItem read GetThreadItem write SetThreadItem;
                property No: Integer read FNo write FNo;
                property Title: string read FTitle write FTitle;
@@ -191,13 +203,22 @@ type
                property IsThreadDatRead: Boolean read FIsThreadDatRead write FIsThreadDatRead;
                property ParentCategory: TCategory read FParentCategory write FParentCategory;
 
+               property        BoardPlugIn     : TBoardPlugIn  read FBoardPlugIn;
+               property        FilePath                : string                                read FFilePath write FFilePath;
+               property        IsLogFile               : Boolean                               read FIsLogFile write FIsLogFile;
+               property        IntData                 : Integer                               read FIntData write FIntData;
+               property        ListData                : TList                                 read FListData write FListData;
+               function        IsBoardPlugInAvailable : Boolean;
+
                function Add(item: TThreadItem): integer;
                procedure Insert(Index: Integer; Item: TThreadItem);
                procedure Delete(index: integer);
                procedure DeleteList(index: integer);
                procedure Clear; override;
                function Find(ItemFileName: string): TThreadItem;
+               function FindThreadFromURL( inURL : string ) : TThreadItem;
                function GetIndex(ItemFileName: string): Integer;
+               function GetIndexFromURL(URL: string): Integer;
                procedure LoadSettings;
                procedure SaveSettings;
                function GetReadCgiURL: string;
@@ -225,6 +246,8 @@ type
        //\83X\83\8c
        TThreadItem = class(TObject)
        private
+               FContext: DWORD;                                        // \83v\83\89\83O\83C\83\93\82ª\8e©\97R\82É\90Ý\92è\82µ\82Ä\82¢\82¢\92l(\8eå\82É\83C\83\93\83X\83^\83\93\83X\82ª\93ü\82é)
+
                FNo: Integer;                                                   //\94Ô\8d\86
                FFileName: string;                              //\83X\83\8c\83b\83h\83t\83@\83C\83\8b\96¼
                FTitle: string;                                         //\83X\83\8c\83b\83h\83^\83C\83g\83\8b
@@ -250,6 +273,10 @@ type
 
                FUpdate: Boolean;
                FExpand: Boolean;
+               FURL                                    : string;                               // \82±\82Ì\83X\83\8c\82ð\83u\83\89\83E\83U\82Å\95\\8e¦\82·\82é\8dÛ\82Ì URL
+               FBoardPlugIn    : TBoardPlugIn; // \82±\82Ì\83X\83\8c\82ð\83T\83|\81[\83g\82·\82é\83v\83\89\83O\83C\83\93
+               FFilePath                       : string;                               // \82±\82Ì\83X\83\8c\82ª\95Û\91\82³\82ê\82Ä\82¢\82é\83p\83X
+               FSizeByte                       : Integer;                      // CreateHTML2 \82ð\8eÀ\8ds\82µ\82Ä\82¢\82é\8dÅ\92\86\82É\88ê\8e\9e\93I\82É\95Û\91\82³\82ê\82é\92l
 
                procedure SetLastModified(d: TDateTime);
                procedure SetRound(b: Boolean);
@@ -257,8 +284,9 @@ type
                procedure SetKokomade(i: Integer);
                procedure SetUnRead(b: Boolean);
                procedure SetScrollTop(i: Integer);
+               procedure Create; overload;
        public
-               constructor Create;
+               constructor Create( inPlugIn : TBoardPlugIn; inURL : string ); overload;
                destructor Destroy; override;
 
                function GetDatURL: string;
@@ -271,6 +299,8 @@ type
                procedure BeginUpdate;
                procedure EndUpdate;
 
+               property Context: DWORD read FContext write FContext;
+
                property No: Integer read FNo write FNo;
                property FileName: string read FFileName write FFileName;
                property Title: string read FTitle write FTitle;
@@ -295,6 +325,12 @@ type
                property DownloadHost: string read FDownloadHost write FDownloadHost;
                property AgeSage: TGikoAgeSage read FAgeSage write FAgeSage;
 //             property SPID: string read FSPID write FSPID;
+
+               property        URL                                     : string                                read FURL write FURL;
+               property        BoardPlugIn     : TBoardPlugIn  read FBoardPlugIn;
+               property        FilePath                : string                                read FFilePath write FFilePath;
+               property        SizeByte                : Integer                               read FSizeByte write FSizeByte;
+               function        IsBoardPlugInAvailable : Boolean;
        end;
 
 
@@ -315,8 +351,13 @@ type
                procedure Clear; override;
        end;}
 
+       function        BBSsFindBoardFromBBSID( inBBSID : string ) : TBoard;
+       function        BBSsFindBoardFromURL( inURL : string ) : TBoard;
+       function        BBSsFindBoardFromTitle( inTitle : string ) : TBoard;
+       function        BBSsFindThreadFromURL( inURL : string ) : TThreadItem;
+
 var
-       BBS2ch: TBBS2ch;
+       BBSs            : array of TBBS;
 
 implementation
 
@@ -324,24 +365,93 @@ uses
        GikoSystem, RoundData;
 
 const
-       BBS2CH_NAME:           string  = '\82Q\82¿\82á\82ñ\82Ë\82é';
-       BBS2CH_LOG_FOLDER:     string  = '2ch';
+       BBS2CH_NAME:                                     string = '\82Q\82¿\82á\82ñ\82Ë\82é';
+       BBS2CH_LOG_FOLDER:               string = '2ch';
+       EXTERNAL_LOG_FOLDER:            string  = 'exboard';
+
+       FOLDER_INI_FILENAME:     string = 'Folder.ini';
+       FOLDER_INDEX_FILENAME: string   = 'Folder.idx';
+       SUBJECT_FILENAME:                       string  = 'subject.txt';
+       PATH_DELIM:                                             string  = '\';
+       //DEFAULT_LIST_COUNT:           Integer = 100;
+
+//     COLUMN_CATEGORY:         array[0..0] of string = ('\83J\83e\83S\83\8a\96¼');
+//     COLUMN_BOARD:                   array[0..3] of string = ('\94Â\96¼', '\8eæ\93¾\90\94', '\8f\84\89ñ\97\\96ñ', '\91O\89ñ\8f\84\89ñ\93ú\8e\9e');
+//     COLUMN_THREADITEM: array[0..3] of string = ('\83X\83\8c\83b\83h\96¼', '\83J\83E\83\93\83g', '\8f\84\89ñ\97\\96ñ', '\91O\89ñ\8f\84\89ñ\93ú\8e\9e');
 
-       FOLDER_INI_FILENAME:   string  = 'Folder.ini';
-       FOLDER_INDEX_FILENAME: string  = 'Folder.idx';
-       SUBJECT_FILENAME:      string  = 'subject.txt';
-       PATH_DELIM:            string  = '\';
-       //DEFAULT_LIST_COUNT:    Integer = 100;
+function       BBSsFindBoardFromBBSID(
+       inBBSID : string
+) : TBoard;
+var
+       i                               : Integer;
+begin
 
-//     COLUMN_CATEGORY:   array[0..0] of string = ('\83J\83e\83S\83\8a\96¼');
-//     COLUMN_BOARD:      array[0..3] of string = ('\94Â\96¼', '\8eæ\93¾\90\94', '\8f\84\89ñ\97\\96ñ', '\91O\89ñ\8f\84\89ñ\93ú\8e\9e');
-//     COLUMN_THREADITEM: array[0..3] of string = ('\83X\83\8c\83b\83h\96¼', '\83J\83E\83\93\83g', '\8f\84\89ñ\97\\96ñ', '\91O\89ñ\8f\84\89ñ\93ú\8e\9e');
+       for i := Length( BBSs ) - 1 downto 0 do begin
+               Result := BBSs[ i ].FindBBSID( inBBSID );
+               if Result <> nil then
+                       Exit;
+       end;
+
+       Result := nil;
+
+end;
+
+function       BBSsFindBoardFromURL(
+       inURL   : string
+) : TBoard;
+var
+       i                       : Integer;
+begin
+
+       for i := Length( BBSs ) - 1 downto 0 do begin
+               Result := BBSs[ i ].FindBoardFromURL( inURL );
+               if Result <> nil then
+                       Exit;
+       end;
+
+       Result := nil;
+
+end;
+
+function       BBSsFindBoardFromTitle(
+       inTitle : string
+) : TBoard;
+var
+       i                               : Integer;
+begin
+
+       for i := Length( BBSs ) - 1 downto 0 do begin
+               Result := BBSs[ i ].FindBoardFromTitle( inTitle );
+               if Result <> nil then
+                       Exit;
+       end;
+
+       Result := nil;
+
+end;
+
+function       BBSsFindThreadFromURL(
+       inURL   : string
+) : TThreadItem;
+var
+       i                       : Integer;
+begin
+
+       for i := Length( BBSs ) - 1 downto 0 do begin
+               Result := BBSs[ i ].FindThreadFromURL( inURL );
+               if Result <> nil then
+                       Exit;
+       end;
+
+       Result := nil;
+
+end;
 
 (*************************************************************************
  *\8b@\94\\96¼\81FTBBS\83R\83\93\83X\83g\83\89\83N\83^
  *Public
  *************************************************************************)
-constructor TBBS2ch.Create(LogFolder: string);
+constructor TBBS.Create(LogFolder: string);
 begin
        Title := BBS2CH_NAME;
        FLogFolder := LogFolder;
@@ -351,7 +461,7 @@ end;
  *\8b@\94\\96¼\81FTBBS\83f\83X\83g\83\89\83N\83^
  *Public
  *************************************************************************)
-destructor TBBS2ch.Destroy;
+destructor TBBS.Destroy;
 begin
        Clear;
        inherited;
@@ -361,23 +471,23 @@ end;
  *\8b@\94\\96¼\81F
  *Public
  *************************************************************************)
-function TBBS2ch.GetCategory(index: integer): TCategory;
+function TBBS.GetCategory(index: integer): TCategory;
 begin
        Result := TCategory(inherited Items[index]);
 end;
 
-procedure TBBS2ch.SetCategory(index: integer; value: TCategory);
+procedure TBBS.SetCategory(index: integer; value: TCategory);
 begin
        inherited Items[index] := value;
 end;
 
-function TBBS2ch.Add(item: TCategory): integer;
+function TBBS.Add(item: TCategory): integer;
 begin
-       Item.ParentBBS2ch := self;
+       Item.ParenTBBS := self;
        Result := inherited Add(item);
 end;
 
-procedure TBBS2ch.Delete(index: integer);
+procedure TBBS.Delete(index: integer);
 begin
        if Items[index] <> nil then
                TCategory(Items[index]).Free;
@@ -385,7 +495,7 @@ begin
        inherited Delete(index);
 end;
 
-procedure TBBS2ch.Clear;
+procedure TBBS.Clear;
 var
        i: integer;
 begin
@@ -393,163 +503,101 @@ begin
                Delete(i);
 end;
 
-function TBBS2ch.Find(key: string): TCategory;
+function TBBS.Find(key: string): TCategory;
 begin
        Result := nil;
 end;
 
-function TBBS2ch.FindBBSID(BBSID: string): TBoard;
+function TBBS.FindBBSID(BBSID: string): TBoard;
 var
-       i: Integer;
-       Category: TCategory;
-       Board: TBoard;
+       i       : Integer;
 begin
-       Result := nil;
-       for i := 0 to Count - 1 do begin
-               Category := Items[i];
-               Board := Category.FindBBSID(BBSID);
-               if Board <> nil then begin
-                       Result := Board;
+       for i := Count - 1 downto 0 do begin
+               Result := Items[ i ].FindBBSID(BBSID);
+               if Result <> nil then
                        Exit;
-               end;
        end;
+       Result := nil;
 end;
 
-function TBBS2ch.FindBoardFromTitle(Title: string): TBoard;
+//*************************************************************************
+// \83^\83C\83g\83\8b\82Ì\88ê\92v\82·\82é\94Â\82ð\92T\82·
+//*************************************************************************)
+function TBBS.FindBoardFromTitle(Title: string): TBoard;
 var
        i: Integer;
-       Category: TCategory;
-       Board: TBoard;
 begin
-       Result := nil;
-       for i := 0 to Count - 1 do begin
-               Category := Items[i];
-               Board := Category.FindBoardFromTitle(Title);
-               if Board <> nil then begin
-                       Result := Board;
+       for i := Count - 1 downto 0 do begin
+               Result := Items[ i ].FindBoardFromTitle(Title);
+               if Result <> nil then
                        Exit;
-               end;
        end;
+       Result := nil;
 end;
 
-function TBBS2ch.FindThreadItem(BBSID: string; FileName: string): TThreadItem;
+//*************************************************************************
+// URL \82ð\8eó\82¯\95t\82¯\82é\94Â\82ð\92T\82·
+//*************************************************************************)
+function TBBS.FindBoardFromURL(inURL: string): TBoard;
 var
-       Board: TBoard;
+       i                                       : Integer;
 begin
+       for i := Count - 1 downto 0 do begin
+               Result := Items[ i ].FindBoardFromURL( inURL );
+               if Result <> nil then
+                       Exit;
+       end;
        Result := nil;
-       Board := FindBBSID(BBSID);
-       if Board = nil then
-               Exit;
-       Result := Board.Find(FileName);
 end;
 
-(*************************************************************************
- *\8b@\94\\96¼\81@\81@\81F\83{\81[\83h\83t\83@\83C\83\8b\93Ç\82Ý\8d\9e\82Ý
- *\89Â\8e\8b\81@\81@\81@\81FPublic
- *\97\9a\97ð\82P\81@\81@\81F\90V\8bK\8dì\90¬
- *************************************************************************)
-procedure TBBS2ch.ReadBoardFile;
+//*************************************************************************
+// URL \82ð\8eó\82¯\95t\82¯\82é\83X\83\8c\83b\83h\82ð\92T\82·
+//*************************************************************************)
+function TBBS.FindThreadFromURL(inURL: string): TThreadItem;
 var
-       i, j: integer;
-       idx: Integer;
-       ini: TMemIniFile;
-       CategoryList: TStringList;
-       BoardList: TStringList;
-       Category: TCategory;
-       Board: TBoard;
-       inistr: string;
-       RoundItem: TRoundItem;
-       BBSList: TStringList;
-       CustomList: TStringList;
-begin
-       ini := TMemIniFile.Create('');
-       BBSList := TStringList.Create;
-       CustomList := TStringList.Create;
-       try
-               if FileExists(GikoSys.GetBoardFileName) then
-                       BBSList.LoadFromFile(GikoSys.GetBoardFileName);
-               if FileExists(GikoSys.GetCustomBoardFileName) then
-                       CustomList.LoadFromFile(GikoSys.GetCustomBoardFileName);
-               BBSList.AddStrings(CustomList);
-               ini.SetStrings(BBSList);
-
-               CategoryList := TStringList.Create;
-               BoardList := TStringList.Create;
-               try
-                       ini.ReadSections(CategoryList);
-                       for i := 0 to CategoryList.Count - 1 do begin
-
-                               ini.ReadSection(CategoryList[i], BoardList);
-                               Category := TCategory.Create;
-                               Category.No := i + 1;
-                               Category.Title := CategoryList[i];
-
-                               for j := 0 to BoardList.Count - 1 do begin
-                                       inistr := ini.ReadString(CategoryList[i], BoardList[j], '');
-                                       Board := TBoard.Create;
-                                       Board.BeginUpdate;
-                                       Board.No := j + 1;
-                                       Board.Title := BoardList[j];
-                                       Board.BBSID := GikoSys.UrlToID(inistr);
-                                       Board.URL := inistr;
-                                       Board.RoundDate := ZERO_DATE;
-
-                                       idx := RoundList.Find(Board);
-                                       if idx <> -1 then begin
-                                               RoundItem := RoundList.Items[idx, grtBoard];
-                                               Board.Round := True;
-                                               Board.RoundName := RoundItem.RoundName;
-                                       end;
-                                       Category.Add(Board);
-                                       Board.EndUpdate;
-                               end;
-                               BBS2ch.Add(Category);
-                       end;
-               finally
-                       BoardList.Free;
-                       CategoryList.Free;
-               end;
-       finally
-               BBSList.Free;
-               CustomList.Free;
-               ini.Free;
+       i       : Integer;
+begin
+       for i := Count - 1 downto 0 do begin
+               Result := Items[ i ].FindThreadFromURL( inURL );
+               if Result <> nil then
+                       Exit;
        end;
+       Result := nil;
 end;
 
-function TBBS2ch.GetBoardFromBBSID(BBSID: string): TBoard;
+function TBBS.FindThreadItem(BBSID: string; FileName: string): TThreadItem;
 var
-       i: integer;
+       Board: TBoard;
 begin
        Result := nil;
-       for i := 0 to BBS2ch.Count - 1 do begin
-               Result := BBS2ch.Items[i].FindBBSID(BBSID);
-               if Result <> nil then
-                       Exit;
-       end;
+       Board := FindBBSID(BBSID);
+       if Board = nil then
+               Exit;
+       Result := Board.Find(FileName);
 end;
 
 (*************************************************************************
  *\83\8d\83O\83t\83H\83\8b\83_\8eæ\93¾
  *
  *************************************************************************)
-function TBBS2ch.GetLogFolder: string;
+function TBBS.GetLogFolder: string;
 begin
        Result := IncludeTrailingPathDelimiter(FLogFolder)
                                        + BBS2CH_LOG_FOLDER + PATH_DELIM;
 end;
 
-procedure TBBS2ch.SetSelectText(s: string);
+procedure TBBS.SetSelectText(s: string);
 begin
        FSelectText := s;
        ShortSelectText := GikoSys.ZenToHan(s);
 end;
 
-{class function TBBS2ch.GetColumnName(Index: Integer): string;
+{class function TBBS.GetColumnName(Index: Integer): string;
 begin
        Result := COLUMN_CATEGORY[Index];
 end;
 
-class function TBBS2ch.GetColumnCount: Integer;
+class function TBBS.GetColumnCount: Integer;
 begin
        Result := Length(COLUMN_CATEGORY);
 end;}
@@ -606,28 +654,64 @@ end;
 
 function TCategory.FindBBSID(BBSID: string): TBoard;
 var
-       i: integer;
+       i       : integer;
 begin
-       Result := nil;
-       for i := 0 to Count - 1 do begin
+       for i := Count - 1 downto 0 do begin
                if Items[i].FBBSID = BBSID then begin
                        Result := Items[i];
                        Exit;
                end;
        end;
+       Result := nil;
 end;
 
+//*************************************************************************
+// \83^\83C\83g\83\8b\82Ì\88ê\92v\82·\82é\94Â\82ð\92T\82·
+//*************************************************************************)
 function TCategory.FindBoardFromTitle(Title: string): TBoard;
 var
-       i: integer;
+       i       : integer;
 begin
-       Result := nil;
-       for i := 0 to Count - 1 do begin
+       for i := Count - 1 downto 0 do begin
                if Items[i].FTitle = Title then begin
                        Result := Items[i];
                        Exit;
                end;
        end;
+       Result := nil;
+end;
+
+//*************************************************************************
+// URL \82ð\8eó\82¯\95t\82¯\82é\94Â\82ð\92T\82·
+//*************************************************************************)
+function TCategory.FindBoardFromURL(inURL: string): TBoard;
+var
+       i       : Integer;
+begin
+       for i := Count - 1 downto 0 do begin
+               if Pos( Items[i].URL, inURL ) = 1 then begin
+                       Result := Items[i];
+                       Exit;
+               end;
+       end;
+       Result := nil;
+end;
+
+//*************************************************************************
+// URL \82ð\8eó\82¯\95t\82¯\82é\83X\83\8c\83b\83h\82ð\92T\82·
+//*************************************************************************)
+function TCategory.FindThreadFromURL(inURL: string): TThreadItem;
+var
+       i                                               : Integer;
+begin
+
+       for i := Count - 1 downto 0 do begin
+               Result := Items[ i ].FindThreadFromURL( inURL );
+               if Result <> nil then
+                       Exit;
+       end;
+       Result := nil;
+
 end;
 
 function TCategory.IsMidoku: Boolean;
@@ -664,7 +748,7 @@ end;}
 //===================
 //TBoard
 //===================
-constructor TBoard.Create;
+procedure TBoard.Create;
 begin
        FNo := 0;
        FTitle := '';
@@ -680,8 +764,49 @@ begin
 //     FItemNoVisible := True;
 
        FUpdate := True;
+
+       FBoardPlugIn := nil;
+end;
+
+// *************************************************************************
+// \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ð\8ew\92è\82µ\82½\83R\83\93\83X\83g\83\89\83N\83^
+// *************************************************************************
+constructor TBoard.Create(
+       inPlugIn        : TBoardPlugIn;
+       inURL                   : string
+);
+var
+       protocol, host, path, document, port, bookmark  : string;
+       BBSID                   : string;
+begin
+
+       Create;
+
+       FBoardPlugIn    := inPlugIn;
+       URL                                             := inURL;
+       BBSID                                   := GikoSys.UrlToID( inURL );
+
+       // \83v\83\89\83O\83C\83\93\82É TBoardItem \82ª\8dì\90¬\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
+       if inPlugIn = nil then begin
+               // subject.txt \82Ì\95Û\91\83p\83X\82ð\90Ý\92è
+               GikoSys.ParseURI( inURL, protocol, host, path, document, port, bookmark );
+               if GikoSys.Is2chHost( host ) then
+                       FilePath :=
+                               IncludeTrailingPathDelimiter( GikoSys.Setting.LogFolder ) +
+                               BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + SUBJECT_FILENAME
+               else
+                       FilePath :=
+                               IncludeTrailingPathDelimiter( GikoSys.Setting.LogFolder ) +
+                               EXTERNAL_LOG_FOLDER + PATH_DELIM + host + PATH_DELIM + BBSID + PATH_DELIM + SUBJECT_FILENAME
+       end else begin
+               inPlugIn.CreateBoardItem( DWORD( Self ) );
+       end;
+
 end;
 
+// *************************************************************************
+// \83f\83X\83g\83\89\83N\83^
+// *************************************************************************
 destructor TBoard.Destroy;
 begin
        if FModified then begin
@@ -689,10 +814,35 @@ begin
                SaveSettings;
        end;
 
+       // \83v\83\89\83O\83C\83\93\82É TBoardItem \82ª\94j\8aü\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
+       if IsBoardPlugInAvailable then
+               BoardPlugIn.DisposeBoardItem( DWORD( Self ) );
+
        Clear;
        inherited;
 end;
 
+// *************************************************************************
+// \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ª\8eg\97p\89Â\94\\82©
+// *************************************************************************
+function       TBoard.IsBoardPlugInAvailable : Boolean;
+begin
+
+       repeat
+               if BoardPlugIn = nil then
+                       Break;
+                       
+               if not Assigned( Pointer( BoardPlugIn.Module ) ) then
+                       Break;
+
+               Result := True;
+               Exit;
+       until True;
+
+       Result := False;
+
+end;
+
 function TBoard.GetThreadItem(index: integer): TThreadItem;
 begin
        Result := TThreadItem(inherited Items[index]);
@@ -765,6 +915,37 @@ begin
        end;
 end;
 
+function TBoard.GetIndexFromURL(URL: string): Integer;
+var
+       i: integer;
+begin
+       Result := -1;
+       for i := 0 to Count - 1 do begin
+               if Items[i].URL = URL then begin
+                       Result := i;
+                       Exit;
+               end;
+       end;
+end;
+
+function TBoard.FindThreadFromURL( inURL : string ) : TThreadItem;
+var
+       i : Integer;
+begin
+
+       if not IsThreadDatRead then
+               GikoSys.ReadSubjectFile( Self );
+               
+       for i := Count - 1 downto 0 do begin
+               if Pos( Items[ i ].URL, inURL ) = 1 then begin
+                       Result := Items[ i ];
+                       Exit;
+               end;
+       end;
+       Result := nil;
+
+end;
+
 {function TBoard.GetMidokuCount: Integer;
 var
        i: integer;
@@ -784,8 +965,11 @@ var
        ini: TMemIniFile;
        FileName: string;
 begin
-       FileName := ParentCategory.ParentBBS2ch.GetLogFolder
-                                               + BBSID + PATH_DELIM + FOLDER_INI_FILENAME;
+       if Length( FilePath ) > 0 then
+               FileName := ExtractFilePath( FilePath ) + FOLDER_INI_FILENAME
+       else
+               FileName := ParentCategory.ParenTBBS.GetLogFolder
+                                                       + BBSID + PATH_DELIM + FOLDER_INI_FILENAME;
 
        if not FileExists(FileName) then
                Exit;
@@ -815,8 +999,11 @@ var
        ini: TMemIniFile;
        FileName: string;
 begin
-       FileName := ParentCategory.ParentBBS2ch.GetLogFolder
-                                               + BBSID + PATH_DELIM;
+       if Length( FilePath ) > 0 then
+               FileName := ExtractFilePath( FilePath )
+       else
+               FileName := ParentCategory.ParenTBBS.GetLogFolder
+                                                       + BBSID + PATH_DELIM;
        if not GikoSys.DirectoryExistsEx(FileName) then
                GikoSys.ForceDirectoriesEx(FileName);
        FileName := FileName + FOLDER_INI_FILENAME;
@@ -855,15 +1042,21 @@ end;
 // \83T\83u\83W\83F\83N\83g\83t\83@\83C\83\8b\96¼\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
 function TBoard.GetSubjectFileName: string;
 begin
-       Result := ParentCategory.ParentBBS2ch.GetLogFolder
-                                       + BBSID + PATH_DELIM + SUBJECT_FILENAME;
+       if Length( FilePath ) > 0 then
+               Result := FilePath
+       else
+               Result := ParentCategory.ParenTBBS.GetLogFolder
+                                               + BBSID + PATH_DELIM + SUBJECT_FILENAME;
 end;
 
 // \83C\83\93\83f\83b\83N\83X\83t\83@\83C\83\8b\96¼(folder.idx)\8eæ\93¾\81i\83p\83X\81{\83t\83@\83C\83\8b\96¼\81j
 function TBoard.GetFolderIndexFileName: string;
 begin
-       Result := ParentCategory.ParentBBS2ch.GetLogFolder
-                                       + BBSID + PATH_DELIM + FOLDER_INDEX_FILENAME;
+       if Length( FilePath ) > 0 then
+               Result := ExtractFilePath( FilePath ) + FOLDER_INDEX_FILENAME
+       else
+               Result := ParentCategory.ParenTBBS.GetLogFolder
+                                               + BBSID + PATH_DELIM + FOLDER_INDEX_FILENAME;
 end;
 
 // \83X\83\8c\97§\82Ä\91\97\90MURL
@@ -938,23 +1131,23 @@ var
        i: Integer;
 begin
        Result := 0;
-        if Length( ParentCategory.ParentBBS2ch.ShortSelectText ) = 0 then
-        begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].NewArrival then
-                               inc(Result);
-               end;
-        end else begin
-               for i := 0 to Count - 1 do begin
-                        if Items[i].NewArrival then
-                        begin
-                                if Items[i].ShortTitle = '' then
-                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
-                                if AnsiPos(ParentCategory.ParentBBS2ch.ShortSelectText, Items[i].ShortTitle) <> 0 then
-                                        inc(Result);
-                        end;
-               end;
-        end;
+                               if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
+                               begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].NewArrival then
+                                                       inc(Result);
+                                       end;
+                               end else begin
+                                       for i := 0 to Count - 1 do begin
+                                                                                               if Items[i].NewArrival then
+                                                                                               begin
+                                                                                                                               if Items[i].ShortTitle = '' then
+                                                                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
+                                                                                                                               if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then
+                                                                                                                                                               inc(Result);
+                                                                                               end;
+                                       end;
+                               end;
 end;
 
 function TBoard.GetLogThreadCount: Integer;
@@ -962,23 +1155,23 @@ var
        i: Integer;
 begin
        Result := 0;
-        if Length( ParentCategory.ParentBBS2ch.ShortSelectText ) = 0 then
-        begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].IsLogFile then
-                               inc(Result);
-               end;
-        end else begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].IsLogFile then
-                        begin
-                                if Items[i].ShortTitle = '' then
-                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
-                                if AnsiPos(ParentCategory.ParentBBS2ch.ShortSelectText, Items[i].ShortTitle) <> 0 then
-                                        inc(Result);
-                        end;
-               end;
-        end;
+                               if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
+                               begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].IsLogFile then
+                                                       inc(Result);
+                                       end;
+                               end else begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].IsLogFile then
+                                                                                               begin
+                                                                                                                               if Items[i].ShortTitle = '' then
+                                                                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
+                                                                                                                               if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then
+                                                                                                                                                               inc(Result);
+                                                                                               end;
+                                       end;
+                               end;
 end;
 
 function TBoard.GetUserThreadCount: Integer;
@@ -986,13 +1179,13 @@ var
        i: Integer;
 begin
        Result := 0;
-        if Length( ParentCategory.ParentBBS2ch.ShortSelectText ) = 0 then
-                Result := Count
-        else
+                               if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
+                                                               Result := Count
+                               else
        for i := 0 to Count - 1 do begin
                if Items[i].ShortTitle = '' then
                        Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
-               if AnsiPos(ParentCategory.ParentBBS2ch.ShortSelectText, Items[i].ShortTitle) <> 0 then
+               if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then
                        inc(Result);
        end;
 end;
@@ -1004,34 +1197,34 @@ var
 begin
        Result := nil;
        Cnt := 0;
-        if Length( ParentCategory.ParentBBS2ch.ShortSelectText ) = 0 then
-        begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].NewArrival then
-                        begin
-                               if Index = Cnt then begin
-                                       Result := Items[i];
-                                       Exit;
-                               end;
-                               inc(Cnt);
-                       end;
-               end;
-        end else begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].NewArrival then
-                        begin
-                               if Items[i].ShortTitle = '' then
-                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
-                               if AnsiPos(ParentCategory.ParentBBS2ch.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
-                                       if Index = Cnt then begin
-                                               Result := Items[i];
-                                               Exit;
-                                       end;
-                                       inc(Cnt);
-                                end;
-                        end;
-               end;
-        end;
+                               if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
+                               begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].NewArrival then
+                                                                                               begin
+                                                       if Index = Cnt then begin
+                                                               Result := Items[i];
+                                                               Exit;
+                                                       end;
+                                                       inc(Cnt);
+                                               end;
+                                       end;
+                               end else begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].NewArrival then
+                                                                                               begin
+                                                                               if Items[i].ShortTitle = '' then
+                                                                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
+                                                                               if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
+                                                                                       if Index = Cnt then begin
+                                                                                               Result := Items[i];
+                                                                                               Exit;
+                                                                                       end;
+                                                                                       inc(Cnt);
+                                                                                                                               end;
+                                                                                               end;
+                                       end;
+                               end;
 end;
 
 function TBoard.GetLogThread(Index: Integer): TThreadItem;
@@ -1039,34 +1232,36 @@ var
        i: Integer;
        Cnt: Integer;
 begin
-        if Length( ParentCategory.ParentBBS2ch.ShortSelectText ) = 0 then
-        begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].IsLogFile then
-                        begin
-                               if Index = Cnt then begin
-                                       Result := Items[i];
-                                       Exit;
-                               end;
-                               inc(Cnt);
-                       end;
-               end;
-        end else begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].IsLogFile then
-                        begin
-                               if Items[i].ShortTitle = '' then
-                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
-                               if AnsiPos(ParentCategory.ParentBBS2ch.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
-                                       if Index = Cnt then begin
-                                               Result := Items[i];
-                                               Exit;
-                                       end;
-                                       inc(Cnt);
-                                end;
-                        end;
-               end;
-        end;
+                               Cnt := 0;
+                               if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
+                               begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].IsLogFile then
+                                                                                               begin
+                                                       if Index = Cnt then begin
+                                                               Result := Items[i];
+                                                               Exit;
+                                                       end;
+                                                       inc(Cnt);
+                                               end;
+                                       end;
+                               end else begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].IsLogFile then
+                                                                                               begin
+                                                                               if Items[i].ShortTitle = '' then
+                                                                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
+                                                                               if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
+                                                                                       if Index = Cnt then begin
+                                                                                               Result := Items[i];
+                                                                                               Exit;
+                                                                                       end;
+                                                                                       inc(Cnt);
+                                                                                                                               end;
+                                                                                               end;
+                                       end;
+                               end;
+                               Result := nil;
 end;
 
 function TBoard.GetUserThread(Index: Integer): TThreadItem;
@@ -1076,29 +1271,29 @@ var
 begin
        Result := nil;
        Cnt := 0;
-        if Length( ParentCategory.ParentBBS2ch.ShortSelectText ) = 0 then
-        begin
-                for i := 0 to Count - 1 do begin
-                        if Index = Cnt then
-                        begin
-                                Result := Items[ i ];
-                                Exit;
-                        end;
-                        inc( Cnt );
-                end;
-        end else begin
-               for i := 0 to Count - 1 do begin
-                       if Items[i].ShortTitle = '' then
-                               Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
-                       if AnsiPos(ParentCategory.ParentBBS2ch.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
-                               if Index = Cnt then begin
-                                       Result := Items[i];
-                                       Exit;
-                               end;
-                               inc(Cnt);
-                       end;
-               end;
-        end;
+                               if Length( ParentCategory.ParenTBBS.ShortSelectText ) = 0 then
+                               begin
+                                                               for i := 0 to Count - 1 do begin
+                                                                                               if Index = Cnt then
+                                                                                               begin
+                                                                                                                               Result := Items[ i ];
+                                                                                                                               Exit;
+                                                                                               end;
+                                                                                               inc( Cnt );
+                                                               end;
+                               end else begin
+                                       for i := 0 to Count - 1 do begin
+                                               if Items[i].ShortTitle = '' then
+                                                       Items[i].ShortTitle := GikoSys.ZenToHan(Items[i].Title);
+                                               if AnsiPos(ParentCategory.ParenTBBS.ShortSelectText, Items[i].ShortTitle) <> 0 then begin
+                                                       if Index = Cnt then begin
+                                                               Result := Items[i];
+                                                               Exit;
+                                                       end;
+                                                       inc(Cnt);
+                                               end;
+                                       end;
+                               end;
 end;
 
 procedure TBoard.BeginUpdate;
@@ -1122,7 +1317,7 @@ begin
 end;}
 
 //constructor TThreadItem.Create(AOwner: TComponent);
-constructor TThreadItem.Create;
+procedure TThreadItem.Create;
 begin
        FNo := 0;
        FFileName := '';
@@ -1141,11 +1336,87 @@ begin
        FNewArrival := False;
 
        FUpdate := True;
+       FURL := '';
+       FBoardPlugIn := nil;
 end;
 
+// *************************************************************************
+// \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ð\8ew\92è\82µ\82½\83R\83\93\83X\83g\83\89\83N\83^
+// *************************************************************************
+constructor TThreadItem.Create(
+       inPlugIn        : TBoardPlugIn;
+       inURL                   : string
+);
+var
+       foundPos                        : Integer;
+       protocol, host, path, document, port, bookmark  : string;
+       BBSID, BBSKey   : string;
+const
+       READ_PATH                                                       = '/test/read.cgi';
+begin
+
+       Create;
+
+       FBoardPlugIn    := inPlugIn;
+       URL                                             := inURL;
+
+       if inPlugIn = nil then begin
+               foundPos := Pos( READ_PATH, inURL );
+               if foundPos > 0 then begin
+                       // dat \82Ì\95Û\91\83p\83X\82ð\90Ý\92è
+                       GikoSys.ParseURI( inURL, protocol, host, path, document, port, bookmark );
+                       GikoSys.Parse2chURL( inURL, path, document, BBSID, BBSKey );
+                       if GikoSys.Is2chHost( host ) then
+                               FilePath :=
+                                       IncludeTrailingPathDelimiter( GikoSys.Setting.LogFolder ) +
+                                       BBS2CH_LOG_FOLDER + PATH_DELIM + BBSID + PATH_DELIM + BBSKey + '.dat'
+                       else
+                               FilePath :=
+                                       IncludeTrailingPathDelimiter( GikoSys.Setting.LogFolder ) +
+                                       EXTERNAL_LOG_FOLDER + PATH_DELIM + host + PATH_DELIM + BBSID + PATH_DELIM + BBSKey + '.dat';
+                       FileName        := BBSKey + '.dat';
+      IsLogFile        := FileExists( FilePath );
+               end;
+       end else begin
+               // \83v\83\89\83O\83C\83\93\82É TThreadItem \82ª\8dì\90¬\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
+               inPlugIn.CreateThreadItem( DWORD( Self ) );
+       end;
+
+end;
+
+// *************************************************************************
+// \83f\83X\83g\83\89\83N\83^
+// *************************************************************************
 destructor TThreadItem.Destroy;
 begin
+
+       // \83v\83\89\83O\83C\83\93\82É TThreadItem \82ª\94j\8aü\82³\82ê\82½\82±\82Æ\82ð\93`\82¦\82é
+       if IsBoardPlugInAvailable then
+               FBoardPlugIn.DisposeThreadItem( DWORD( Self ) );
+
        inherited;
+
+end;
+
+// *************************************************************************
+// \8aO\95\94\94Â\83v\83\89\83O\83C\83\93\82ª\8eg\97p\89Â\94\\82©
+// *************************************************************************
+function       TThreadItem.IsBoardPlugInAvailable : Boolean;
+begin
+
+       repeat
+               if BoardPlugIn = nil then
+                       Break;
+
+               if not Assigned( Pointer( BoardPlugIn.Module ) ) then
+                       Break;
+
+               Result := True;
+               Exit;
+       until True;
+
+       Result := False;
+
 end;
 
 function TThreadItem.GetDatURL: string;
@@ -1262,8 +1533,8 @@ end;
 procedure TThreadItem.DeleteLogFile;
 begin
        DeleteFile(GetThreadFileName);
-    if FileExists(ChangeFileExt(GetThreadFileName,'.NG')) = true then
-       DeleteFile(ChangeFileExt(GetThreadFileName,'.NG'));
+               if FileExists(ChangeFileExt(GetThreadFileName,'.NG')) = true then
+                       DeleteFile(ChangeFileExt(GetThreadFileName,'.NG'));
        FRoundDate := ZERO_DATE;
        FLastModified := ZERO_DATE;
        FSize := 0;
@@ -1284,8 +1555,11 @@ end;
 
 function TThreadItem.GetThreadFileName: string;
 begin
-       Result := ParentBoard.ParentCategory.ParentBBS2ch.GetLogFolder
-                                       + ParentBoard.BBSID + PATH_DELIM + FileName;
+       if Length( FilePath ) > 0 then
+               Result := FilePath
+       else
+               Result := ParentBoard.ParentCategory.ParenTBBS.GetLogFolder
+                                               + ParentBoard.BBSID + PATH_DELIM + FileName;
 end;
 
 procedure TThreadItem.SetLastModified(d: TDateTime);
@@ -1359,7 +1633,7 @@ begin
 end;
 
 {initialization
-       BBS2ch := TBBS2ch.Create;
+       BBS2ch := TBBS.Create;
 
 finalization
        if BBS2ch <> nil then