OSDN Git Service

1.60.0.783をマージ
[gikonavigoeson/gikonavi.git] / res / ExternalBoardPlugIn / MachiBBSPlugIn.dpr
index 7ed4b42..1956c36 100644 (file)
@@ -11,7 +11,8 @@ uses
        PlugInMain in 'PlugInMain.pas',
        ThreadItem in 'ThreadItem.pas',
        BoardItem in 'BoardItem.pas',
-       FilePath in 'FilePath.pas';
+       FilePath in 'FilePath.pas',
+    MojuUtils in '..\..\MojuUtils.pas';
 
 {$R *.res}
 
@@ -23,7 +24,7 @@ type
        private
                FIsTemporary    : Boolean;
                FDat                                    : TStringList;
-
+               //FFilePath             : String;
        public
                constructor     Create( inInstance : DWORD );
                destructor      Destroy; override;
@@ -32,13 +33,16 @@ type
                function        Download : TDownloadState;
                function        Write( inName : string; inMail : string; inMessage : string ) : TDownloadState;
                function        GetRes( inNo : Integer ) : string;
+               function        GetDat( inNo : Integer ) : string;
                function        GetHeader( inOptionalHeader : string ) : string;
                function        GetFooter( inOptionalFooter : string ) : string;
                function        GetBoardURL : string;
 
-               procedure       To2chDat( ioHTML : TStringList );
+               procedure       To2chDat( ioHTML : TStringList; inStartNo : Integer = 1 );
                procedure       LoadDat;
                procedure       FreeDat;
+               function        ReadURL : string;
+               //property      FilePath : string read FFilePath;
        end;
 
        // =========================================================================
@@ -79,7 +83,7 @@ const
        MAJOR_VERSION                   = 1;
        MINOR_VERSION                   = 0;
        RELEASE_VERSION         = 'beta';
-       REVISION_VERSION        = 7;
+       REVISION_VERSION        = 20;
 
 // =========================================================================
 // \8eG\97p\8aÖ\90\94
@@ -105,7 +109,7 @@ end;
 // *************************************************************************
 function MyLogFolder : string;
 var
-       folder : string;
+       folder : PChar;
 begin
 
        folder := LogFolder;
@@ -113,6 +117,7 @@ begin
                Result := ''
        else
                Result := folder + LOG_DIR;
+    DisposeResultString(folder);
 
 end;
 
@@ -255,30 +260,111 @@ end;
 // \8ew\92è\82µ\82½ URL \82ð\82±\82Ì\83v\83\89\83O\83C\83\93\82Å\8eó\82¯\95t\82¯\82é\82©\82Ç\82¤\82©
 // *************************************************************************
 function OnAcceptURL(
-       inURL : PChar                                           // \94»\92f\82ð\8bÂ\82¢\82Å\82¢\82é URL
-): Boolean; stdcall;                   // \8eó\82¯\95t\82¯\82é\82È\82ç True
+       inURL                   : PChar                         // \94»\92f\82ð\8bÂ\82¢\82Å\82¢\82é URL
+): TAcceptType; stdcall;       // URL \82Ì\8eí\97Þ
 var
-       URI : TIdURI;
-       foundPos : Integer;
+       uri                             : TIdURI;
+       uriList         : TStringList;
+       foundPos        : Integer;
 const
-       BBS_HOST = 'machi.to';
+       BBS_HOST                = 'machi.to';
+       THREAD_MARK     = '/bbs/read.pl';
+    THREAD_MARK2= '/bbs/read.cgi';
 begin
 
        try
-               // \97á\82Æ\82µ\82Ä\83z\83X\83g\96¼\82ª machi.to \82Å\8fI\82í\82é\8fê\8d\87\82Í\8eó\82¯\95t\82¯\82é\82æ\82¤\82É\82µ\82Ä\82¢\82é
-               URI := TIdURI.Create( inURL );
+               // \83z\83X\83g\96¼\82ª machi.to \82Å\8fI\82í\82é\8fê\8d\87\82Í\8eó\82¯\95t\82¯\82é\82æ\82¤\82É\82µ\82Ä\82¢\82é
+               uri                     := TIdURI.Create( inURL );
+               uriList := TStringList.Create;
                try
-                       foundPos := Pos( BBS_HOST, URI.Host );
-                       Result := (foundPos > 0) and (Length( URI.Host ) - foundPos + 1 = Length( BBS_HOST ))
+                       ExtractHttpFields( ['/'], [], uri.Path, uriList );
+                       foundPos := AnsiPos( BBS_HOST, uri.Host );
+                       if (foundPos > 0) and (Length( uri.Host ) - foundPos + 1 = Length( BBS_HOST )) then begin
+                               foundPos := Pos( THREAD_MARK, inURL );
+                if (foundPos = 0) then begin
+                    // \90VURL\91Î\89\9e
+                    foundPos := Pos( THREAD_MARK2, inURL );
+                end;
+                               if foundPos > 0 then
+                                       Result := atThread
+                               else if (uriList.Count > 1) and (uri.Path <> '/') then  // \8dÅ\8cã\82ª '/' \82Å\95Â\82ß\82ç\82ê\82Ä\82é\82È\82ç 3
+                                       Result := atBoard
+                               else
+                                       Result := atBBS;
+                       end else begin
+                               Result := atNoAccept;
+                       end;
                finally
-                       URI.Free;
+                       uri.Free;
+                       uriList.Free;
                end;
        except
-               Result := False;
+               Result := atNoAccept;
        end;
 
 end;
 
+// *************************************************************************
+// \8ew\92è\82µ\82½ URL \82ðBoard\82ÌURL\82É\95Ï\8a·
+// *************************************************************************
+procedure OnExtractBoardURL(
+       inURL   : PChar;
+       var outURL      : PChar
+); stdcall;
+var
+       uri                     : TIdURI;
+       uriList         : TStringList;
+       URL         : String;
+const
+       THREAD_MARK     = '/bbs/read.pl';
+    THREAD_MARK2= '/bbs/read.cgi';
+begin
+       URL := string(inURL);
+       if AnsiPos(THREAD_MARK, URL) > 0 then begin
+               if Copy( inURL, Length( inURL ), 1 ) = '/' then
+                       uri := TIdURI.Create( URL )
+               else
+                       uri := TIdURI.Create( URL + '/' );
+
+               uriList := TStringList.Create;
+               try
+                       ExtractHttpFields(
+                               ['&'], [],
+                               Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ),uriList );
+                       // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
+                       // http://hokkaido.machi.to/hokkaidou/
+                       URL := uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/';
+                       outURL := CreateResultString(URL);
+               finally
+                       uri.Free;
+                       uriList.Free;
+               end;
+    end else if AnsiPos(THREAD_MARK2, URL) > 0 then begin
+               if Copy( inURL, Length( inURL ), 1 ) = '/' then
+                       uri := TIdURI.Create( URL )
+               else
+                       uri := TIdURI.Create( URL + '/' );
+
+        uriList := TStringList.Create;
+               try
+                       // http://kanto.machi.to/bbs/read.cgi/kana/1215253035/l50
+                       // http://kanto.machi.to/kana/
+            uriList.Delimiter := '/';
+            uriList.DelimitedText  := uri.Path;
+                       URL := uri.Protocol + '://' + uri.Host + '/';
+            if (uriList.Count >= 4) then begin
+                URL := URL + uriList[3] + '/';
+            end;
+                       outURL := CreateResultString(URL);
+               finally
+                       uri.Free;
+            uriList.Free;
+               end;
+       end else begin
+       outURL := CreateResultString(URL);
+       end;
+
+end;
 
 
 // =========================================================================
@@ -294,6 +380,7 @@ constructor TMachiBBSThreadItem.Create(
 var
        uri                                     : TIdURI;
        uriList                 : TStringList;
+       FilePath                : String;
 begin
 
        inherited;
@@ -301,13 +388,15 @@ begin
        OnDownload              := Download;
        OnWrite                         := Write;
        OnGetRes                        := GetRes;
+       OnGetDat                        := GetDat;
        OnGetHeader             := GetHeader;
        OnGetFooter             := GetFooter;
        OnGetBoardURL   := GetBoardURL;
 
-       FilePath                        := '';
+       //FFilePath                     := '';
        FIsTemporary    := False;
        FDat                                    := nil;
+       URL                                             := ReadURL + '&LAST=50';
 
        uri                     := TIdURI.Create( URL );
        uriList := TStringList.Create;
@@ -315,7 +404,7 @@ begin
                // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
                ExtractHttpFields(
                        ['&'], [],
-                       Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+                       Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
                FileName        := uriList.Values[ 'KEY' ] + '.dat';
                FilePath        := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
                IsLogFile       := FileExists( FilePath );
@@ -357,6 +446,7 @@ var
        uriList                         : TStringList;
        datURL                          : string;
        foundPos                        : Integer;
+       FilePath                        : String;
        procedure       downAndParse;
        begin
                responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
@@ -368,24 +458,23 @@ var
                                        downResult.Text := string( tmp );
 
                                        // \83^\83C\83g\83\8b\82Ì\8eæ\93¾
-                                       foundPos                                := Pos( '<title>', downResult.Text ) + Length( '<title>' );
+                                       foundPos                                := AnsiPos( '<title>', downResult.Text ) + Length( '<title>' );
                                        Title                                           := Copy(
                                                downResult.Text,
                                                foundPos,
-                                               Pos( '</title>', downResult.Text ) - foundPos );
+                                               AnsiPos( '</title>', downResult.Text ) - foundPos );
 
                                        // \83\8c\83X\82Ì\8aJ\8en\88Ê\92u
-                                       foundPos                                := Pos( '<dt', downResult.Text );
+                                       foundPos                                := AnsiPos( '<dt', downResult.Text );
                                        downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
                                        if foundPos > 0 then begin
                                                // \83\8c\83X\82Ì\8fI\97¹\88Ê\92u
-                                               foundPos := Pos( '<table', downResult.Text ) - 1;
+                                               foundPos := AnsiPos( '<table', downResult.Text ) - 1;
                                                if foundPos > 0 then
                                                        downResult.Text := Copy( downResult.Text, 1, foundPos );
-
                                                // \82Ü\82¿BBS\82Í dat \92¼\93Ç\82Ý\82ª\8fo\97\88\82È\82¢\82µ\81Acgi \88È\8aO\82É\8d·\95ª\93Ç\82Ý\8d\9e\82Ý\82Ì\95û\96@\82ª\82 \82é\82í\82¯\82Å\82à\96³\82¢\82Ì\82Å
                                                // \91f\82Ì\82Ü\82Ü\82ð\96³\97\9d\82É\95Û\82Æ\82¤\82Æ\82Í\82¹\82¸\82É 2ch \82Ì dat \8c`\8e®\82É\95Ï\8a·\82µ\82½\82à\82Ì\82ð\95Û\91\82µ\82Ä\82µ\82Ü\82¤
-                                               To2chDat( downResult );
+                                               To2chDat( downResult, Count + 1 );
                                                content.Text := content.Text + downResult.Text;
                                        end;
                                finally
@@ -409,7 +498,7 @@ begin
        try
                ExtractHttpFields(
                        ['&'], [],
-                       Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+                       Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
                FileName := uriList.Values[ 'KEY' ] + '.dat';
                if MyLogFolder = '' then begin
                        // \82Ç\82±\82É\95Û\91\82µ\82Ä\82¢\82¢\82Ì\82©\95ª\82©\82ç\82È\82¢\82Ì\82Å\88ê\8e\9e\83t\83@\83C\83\8b\82É\95Û\91
@@ -429,13 +518,13 @@ begin
                if Count = 0 then
                        // 1\81`
                        datURL          :=
-                               uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+                               uri.Protocol + '://' + uri.Host + '/bbs/read.cgi?' +
                                'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
                                '&START=' + IntToStr( 1 )
                else
                        // \90V\92\85\82Ì\82Ý
                        datURL          :=
-                               uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+                               uri.Protocol + '://' + uri.Host + '/bbs/read.cgi?' +
                                'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
                                '&START=' + IntToStr( Count + 1 ) + '&NOFIRST=TRUE';
                // \83_\83E\83\93\83\8d\81[\83h
@@ -456,28 +545,29 @@ begin
                                NewReceive      := 1;
                                Count                           := content.Count;
                        end else begin
-                               if content.Count > 0 then begin
-                                       Result := dsDiffComplete;
-                                       // \92Ç\8bL
-                                       logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite );
-                                       try
-                                               logStream.Position      := logStream.Size;
-                                               logStream.Write( PChar( content.Text )^, Length( content.Text ) );
-                                       finally
-                                               logStream.Free;
-                                       end;
-                                       NewReceive      := Count + 1;
-                                       Count                           := Count + content.Count;
-                               end else begin
-                                       Result := dsNotModify;
-                               end;
+                if (content.Count > 1) or (Trim(content.Text) <> '') then begin
+                               Result := dsDiffComplete;
+                    // \92Ç\8bL
+                    logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite );
+                    try
+                        logStream.Position     := logStream.Size;
+                        logStream.Write( PChar( content.Text )^, Length( content.Text ) );
+                    finally
+                        logStream.Free;
+                    end;
+                    NewReceive := Count + 1;
+                    Count                              := Count + content.Count;
+                end else begin
+                    Result := dsNotModify;
+                end;
                        end;
-
-                       // CGI \82©\82ç\82Í\90³\82µ\82¢\93ú\95t\82ª\93¾\82ç\82ê\82È\82¢\82Ì\82Å\8c»\8dÝ\82É\90Ý\92è
-                       LastModified    := Now;
-                       RoundDate                       := Now;
-                       IsLogFile                       := True;
-                       NewResCount             := content.Count;
+            if (Result <> dsNotModify) then begin
+                       // CGI \82©\82ç\82Í\90³\82µ\82¢\93ú\95t\82ª\93¾\82ç\82ê\82È\82¢\82Ì\82Å\8c»\8dÝ\82É\90Ý\92è
+                       LastModified    := Now;
+                       NewResCount             := content.Count;
+            end;
+               end else begin
+                       Result := dsNotModify;
                end;
        finally
                uri.Free;
@@ -508,7 +598,7 @@ begin
        try
                ExtractHttpFields(
                        ['&'], [],
-                       Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+                       Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
 
                postURL         := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
                postData        :=
@@ -521,7 +611,7 @@ begin
                        '&submit='      + HttpEncode( '\8f\91\82«\8d\9e\82Þ' );
 
                // \93Æ\8e©\82É\92Ê\90M\82µ\82È\82¢\8fê\8d\87\82Í InternalPost \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
-               InternalPost( PChar( postURL ), PChar( postData ), postResult );
+               InternalPost( PChar( postURL ), PChar( postData ),PChar(URL), postResult );
                DisposeResultString( postResult );
 
                Result := dsComplete
@@ -546,14 +636,14 @@ begin
        // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
        // InternalAbon \82¨\82æ\82Ñ Dat2HTML \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
        LoadDat;
-       if FDat = nil then begin
+       if (FDat = nil) or (inNo - 1 < 0 ) or (inNo - 1 >= FDat.Count) then begin
                // \83\8d\83O\82É\91\8dÝ\82µ\82È\82¢\82Ì\82Å\82±\82Ì\82Ü\82Ü\8fI\97¹
                Result := '';
                Exit;
        end;
        res                     := FDat[ inNo - 1 ];
-       tmp                     := InternalAbon( PChar( res ) );
-       try
+       tmp                     := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
+    try
                Result  := Dat2HTML( string( tmp ), inNo );
        finally
                DisposeResultString( tmp );
@@ -562,6 +652,35 @@ begin
 end;
 
 // *************************************************************************
+// \83\8c\83X\94Ô\8d\86 inNo \82É\91Î\82·\82é Dat \82ð\97v\8b\81\82³\82ê\82½
+// *************************************************************************
+function TMachiBBSThreadItem.GetDat(
+       inNo            : Integer               // \97v\8b\81\82³\82ê\82½\83\8c\83X\94Ô\8d\86
+) : string;                                            // \82Q\82¿\82á\82ñ\82Ë\82é\82ÌDat\8c`\8e®
+var
+       //res: string;
+       tmp: PChar;
+begin
+       //Result        := '';
+       // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
+       LoadDat;
+       if (FDat = nil) or (inNo - 1 < 0 ) or (inNo - 1 >= FDat.Count)  then begin
+               // \83\8d\83O\82É\91\8dÝ\82µ\82È\82¢\82Ì\82Å\82±\82Ì\82Ü\82Ü\8fI\97¹
+               tmp := CreateResultString('');
+               Result := tmp;
+               DisposeResultString(tmp);
+               Exit;
+       end;
+       tmp := CreateResultString(FDat[ inNo - 1]);
+       try
+               Result := string(tmp);
+       finally
+               DisposeResultString(tmp);
+       end;
+
+end;
+
+// *************************************************************************
 // \83X\83\8c\83b\83h\82Ì\83w\83b\83_ html \82ð\97v\8b\81\82³\82ê\82½
 // *************************************************************************
 function TMachiBBSThreadItem.GetHeader(
@@ -612,8 +731,9 @@ function    TMachiBBSThreadItem.GetBoardURL : string;
 var
        uri                                             : TIdURI;
        uriList                         : TStringList;
+       tmp: PChar;
 begin
-
+    tmp := nil;
        if Copy( URL, Length( URL ), 1 ) = '/' then
                uri := TIdURI.Create( URL )
        else
@@ -622,13 +742,15 @@ begin
        try
                ExtractHttpFields(
                        ['&'], [],
-                       Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+                       Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
                FileName := uriList.Values[ 'KEY' ] + '.dat';
                // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
                // http://hokkaido.machi.to/hokkaidou/
-               Result          := CreateResultString(
+               tmp             := CreateResultString(
                        uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/' );
+               Result := string(tmp);
        finally
+               DisposeResultString(tmp);
                uri.Free;
                uriList.Free;
        end;
@@ -639,47 +761,83 @@ end;
 // \82Ü\82¿BBS\82Ì HTML \82ð 2ch \82Ì dat \8c`\8e®\82É
 // *************************************************************************
 procedure      TMachiBBSThreadItem.To2chDat(
-       ioHTML                  : TStringList
+       ioHTML                          : TStringList;
+       inStartNo                       : Integer = 1
 );
 var
-       i, bound                : Integer;
-       foundPos                : Integer;
-       strTmp                  : string;
-       res                                     : TStringList;
+       i, bound                        : Integer;
+       foundPos,foundPos2                      : Integer;
+       strTmp                          : string;
+       res                                             : TStringList;
+       no                                              : Integer;
 const
-       MAIL_TAG                = '<a href="mailto:';
+       MAIL_TAG                        = '<a href="mailto:';
 begin
 
        //===== 2ch \82Ì dat \8c`\8e®\82É\95Ï\8a·
        // \83z\83X\83g\96¼\82Ì\8cã\82Å\89ü\8ds\82³\82ê\82Ä\82¢\82½\82è\82·\82é\82Ì\82Å\89ü\8ds\82ð\82·\82×\82Ä\8eæ\82è\8f\9c\82­
-       ioHTML.Text     := StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, #13#10, '');
+       //StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
        // \91ã\82í\82è\82É <dt> \82ð\8ds\82Ì\8bæ\90Ø\82è\82É\82·\82é
-       ioHTML.Text     := StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<dt>', #10 );
+       //StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
        // <dt> \82©\82ç\8en\82Ü\82Á\82Ä\82¢\82é\82Ì\82Å\8dÅ\8f\89\82Í\8bó\82Ì\82Í\82¸
        if Length( ioHTML[ 0 ] ) = 0 then
                ioHTML.Delete( 0 );
+
+       // \8cy\82­\82 \82Ú\81[\82ñ\83`\83F\83b\83N
+       // \81¦\91å\8eG\94c\82¾\82©\82ç\82¿\82á\82ñ\82Æ\8fo\97\88\82Ä\82È\82¢\82©\82à
+       try
+               i                       := 0;
+               while i < ioHTML.Count do begin
+                       foundPos := AnsiPos( ' ', ioHTML[ i ] );
+                       if foundPos > 0 then begin
+                               no := StrToInt( Copy( ioHTML[ i ], 1, foundPos - 1 ) );
+                               if inStartNo < no then
+                                       ioHTML.Insert( i, '<><><><>' );
+                       end;
+                       Inc( i );
+                       Inc( inStartNo );
+               end;
+       except
+               // \82 \82Ú\81[\82ñ\83`\83F\83b\83N\82Å\96â\91è\82ª\94­\90\82µ\82Ä\82à\90æ\82Ö\90i\82ß\82½\82¢\82Ì\82Å
+       end;
+
+
        // \83g\83\8a\83b\83v\82Ì\8cã\82Ì '<b> </b>' \82ð\8bó\82É
-       ioHTML.Text     := StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
+    if AnsiPos('\81\9f</b>', ioHTML.Text) <> 0 then begin
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<b> </b></font>', '</b></font>', true );
+        ioHTML.Text    := CustomStringReplace( ioHTML.Text, '<b> </B></a>', '</b></a>', true );
+    end;
+       //ioHTML.Text   := CustomStringReplace( ioHTML.Text, '<b> </b>', '', true );
+       //StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
        // '<b>' \82Í\83\81\81[\83\8b\82Æ\96¼\91O\82Ì\8bæ\90Ø\82è
-       ioHTML.Text     := StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<b>', '<>', true );
+       //StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
        // \83\81\81[\83\8b\82Æ\96¼\91O\82É\82Â\82¢\82Ä\82­\82é\95Â\82\83^\83O\82ð\93\8a\8de\93ú\82Æ\82Ì\8bæ\90Ø\82è\82É
-       ioHTML.Text     := StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
-       ioHTML.Text     := StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, '</b></a>', '<>', true );
+       //StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, '</b>', '<>', true );
+    ioHTML.Text        := CustomStringReplace( ioHTML.Text, '\81\9f<>', '\81\9f</b>', true );
+       //StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
        // '<dd>' \82ð\96{\95\82Æ\82Ì\8bæ\90Ø\82è\82É
-       ioHTML.Text     := StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
+       ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<dd>', '<>', true );
+       //StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
 
        res := TStringList.Create;
        try
                bound := ioHTML.Count - 1;
                for i := 0 to bound do begin
-                       res.Text := StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
+            // \83X\83N\83\8a\83v\83g\82ª\8aÜ\82Ü\82ê\82Ä\82¢\82½\82ç\8dí\8f\9c\82·\82é\81i\8dL\8d\90\91Î\8dô\81j
+                       res.Text := CustomStringReplace( ioHTML[ i ], '<>', #10 );
+                                               //StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
                        if res.Count >= 3 then begin    // 3 \96¢\96\9e\82Í\82 \82è\82¦\82È\82¢\82Æ\8ev\82¤\82¯\82Ç\88À\91S\82Ì\82½\82ß
-                               foundPos := Pos( MAIL_TAG, res[ 0 ] );
+                               foundPos := AnsiPos( MAIL_TAG, res[ 0 ] );
                                if foundPos > 0 then begin
                                        // \83\81\81[\83\8b\83A\83h\83\8c\83X\82ð\94²\82«\8fo\82·
                                        foundPos        := foundPos + Length( MAIL_TAG );
                                        res[ 0 ]        := Copy( res[ 0 ], foundPos, Length( res[ 0 ] ) );
-                                       strTmp          := Copy( res[ 0 ], 1, Pos( '">', res[ 0 ] ) - 1 );
+                                       strTmp          := Copy( res[ 0 ], 1, AnsiPos( '">', res[ 0 ] ) - 1 );
                                        // \83\81\81[\83\8b\82Æ\96¼\91O\82ª\8bt\82È\82Ì\82Å\82Ð\82Á\82­\82è\95Ô\82µ\82Ä\96ß\82·
                                        res[ 0 ]        := res[ 1 ];
                                        res[ 1 ]        := strTmp;
@@ -688,10 +846,25 @@ begin
                                        res[ 0 ]        := res[ 1 ];
                                        res[ 1 ]        := '';
                                end;
-                               res[ 2 ] := StringReplace( res[ 2 ], '[', 'ID:', [] );
+                               res[ 2 ] := StringReplace( res[ 2 ], '[', 'IP:', [] );
                                res[ 2 ] := StringReplace( res[ 2 ], ']', '', [] );
+
+                if AnsiPos('</font> \93\8a\8de\93ú\81F', res[ 2 ]) = 1 then begin
+                       res[ 2 ] := StringReplace( res[ 2 ], '</font> \93\8a\8de\93ú\81F', '', [] );
+                end else if AnsiPos(' \93\8a\8de\93ú\81F', res[ 2 ]) = 1 then begin
+                    res[ 2 ] := StringReplace( res[ 2 ], ' \93\8a\8de\93ú\81F', '', [] );
+                end;
                        end;
-                       ioHTML[ i ] := StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
+                       ioHTML[ i ] := CustomStringReplace( res.Text, #13#10, '<>');
+            // \8dL\8d\90\83X\83N\83\8a\83v\83g\91Î\8dô
+            foundPos := Pos( '<script', ioHTML[ i ] );
+            if foundPos > 0 then begin
+                foundPos2 := Pos( '</script>', ioHTML[ i ] );
+                if (foundPos2 > foundPos) then begin
+                    ioHTML[ i ] := Copy(ioHTML[ i ], 1, foundPos-1) +
+                                   Copy(ioHTML[ i ], foundPos2 + 9, Length(ioHTML[ i ]));
+                end;
+            end;
                end;
        finally
                res.Free;
@@ -729,6 +902,54 @@ begin
 end;
 
 // *************************************************************************
+// \88À\91S\82È( '/' \82Å\8fI\82í\82é )\93Ç\82Ý\8d\9e\82Ý\82Ì URL
+// *************************************************************************
+function       TMachiBBSThreadItem.ReadURL : string;
+var
+       uri                             : TIdURI;
+       uriList         : TStringList;
+       foundPos        : Integer;
+const
+    THREAD_MARK2= '/bbs/read.cgi';
+begin
+
+       foundPos := AnsiPos( '?', URL );
+       if foundPos > 0 then begin
+               uri := TIdURI.Create( URL );
+               uriList := TStringList.Create;
+               try
+                       ExtractHttpFields( ['&'], [], Copy( URL, foundPos + 1, MaxInt ), uriList );
+                       Result :=
+                               uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+                               'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ];
+               finally
+                       uri.Free;
+                       uriList.Free;
+               end;
+       end else begin
+        // \90V\8c`\8e® ?
+        foundPos := AnsiPos(THREAD_MARK2, URL);
+       if (foundPos > 0) then begin
+            uri := TIdURI.Create( URL );
+            uriList := TStringList.Create;
+            try
+                uriList.Delimiter := '/';
+                uriList.DelimitedText  := uri.Path;
+                if (uriList.Count >= 5) then begin
+                           Result :=
+                                   uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+                                   'BBS=' + uriList[3] + '&KEY=' + uriList[4];
+                end;
+            finally
+                       uri.Free;
+                       uriList.Free;
+            end;
+        end;
+    end;
+
+end;
+
+// *************************************************************************
 // TThreadItem \82ª\90\90¬\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSThreadItem \82ð\90\90¬\82·\82é)
 // *************************************************************************
 procedure ThreadItemOnCreateOfTMachiBBSThreadItem(
@@ -783,6 +1004,7 @@ begin
        FilePath                        := '';
        FIsTemporary    := False;
        FDat                                    := nil;
+    Is2ch                      := False;
 
        uri                     := TIdURI.Create( SubjectURL );
        uriList := TStringList.Create;
@@ -907,7 +1129,7 @@ begin
        try
                ExtractHttpFields(
                        ['&'], [],
-                       Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+                       Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
 
                postURL         := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
                postData        :=
@@ -920,7 +1142,7 @@ begin
                        '&submit='      + HttpEncode( '\90V\8bK\8f\91\82«\8d\9e\82Ý' );
 
                // \93Æ\8e©\82É\92Ê\90M\82µ\82È\82¢\8fê\8d\87\82Í InternalPost \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
-               InternalPost( PChar( postURL ), PChar( postData ), postResult );
+               InternalPost( PChar( postURL ), PChar( postData ),PChar(URL), postResult );
                DisposeResultString( postResult );
 
                Result := dsComplete
@@ -944,7 +1166,7 @@ var
        found                           : Integer;
 begin
 
-       found := Pos( '.', inFileName );
+       found := AnsiPos( '.', inFileName );
        if found > 0 then
                inFileName := Copy( inFileName, 1, found - 1 );
 
@@ -1000,7 +1222,7 @@ begin
                end;
 
                // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í EnumThread \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
-               inherited EnumThread( inCallBack, FDat.Text );
+               inherited EnumThread( inCallBack, CustomStringReplace( FDat.Text, ',', '<>' ) );
        except
        end;
 
@@ -1107,8 +1329,8 @@ end;
 
 exports
        OnVersionInfo,
-       OnAcceptURL;
-
+       OnAcceptURL,
+    OnExtractBoardURL;
 begin
 
        try