OSDN Git Service

まちBBSでエラー文字列を受信した場合に削除レスと同じ扱いにしてしまう不具合を修正
[gikonavigoeson/gikonavi.git] / res / ExternalBoardPlugIn / MachiBBSPlugIn.dpr
index 73795be..f3b1a7e 100644 (file)
@@ -24,7 +24,7 @@ type
        private
                FIsTemporary    : Boolean;
                FDat                                    : TStringList;
-
+               //FFilePath             : String;
        public
                constructor     Create( inInstance : DWORD );
                destructor      Destroy; override;
@@ -33,15 +33,17 @@ type
                function        Download : TDownloadState;
                function        Write( inName : string; inMail : string; inMessage : string ) : TDownloadState;
                function        GetRes( inNo : Integer ) : string;
-        function       GetDat( 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; inStartNo : Integer = 1 );
+//             procedure       To2chDat( ioHTML : TStringList; inStartNo : Integer = 1 );
+               procedure       To2chDat2( var ioDat: TStringList );
                procedure       LoadDat;
                procedure       FreeDat;
                function        ReadURL : string;
+               //property      FilePath : string read FFilePath;
        end;
 
        // =========================================================================
@@ -63,6 +65,8 @@ type
                procedure       EnumThread( inCallBack : TBoardItemEnumThreadCallBack );
 
                function        SubjectURL : string;
+               function        SubjectURL2 : string;
+        procedure   ChangeSubjectFormat(var dat: TStringList);
        end;
 
        // =========================================================================
@@ -82,7 +86,7 @@ const
        MAJOR_VERSION                   = 1;
        MINOR_VERSION                   = 0;
        RELEASE_VERSION         = 'beta';
-       REVISION_VERSION        = 11;
+       REVISION_VERSION        = 25;
 
 // =========================================================================
 // \8eG\97p\8aÖ\90\94
@@ -108,7 +112,7 @@ end;
 // *************************************************************************
 function MyLogFolder : string;
 var
-       folder : string;
+       folder : PChar;
 begin
 
        folder := LogFolder;
@@ -116,6 +120,7 @@ begin
                Result := ''
        else
                Result := folder + LOG_DIR;
+    DisposeResultString(folder);
 
 end;
 
@@ -266,18 +271,23 @@ var
        foundPos        : Integer;
 const
        BBS_HOST                = 'machi.to';
+       BBS_HOST2               = 'machibbs.com';
        THREAD_MARK     = '/bbs/read.pl';
+    THREAD_MARK2= '/bbs/read.cgi';
 begin
-
        try
                // \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
-                       ExtractHttpFields( ['/'], [], uri.Path, uriList );
+                       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
@@ -285,7 +295,23 @@ begin
                                else
                                        Result := atBBS;
                        end else begin
-                               Result := atNoAccept;
+                foundPos := AnsiPos( BBS_HOST2, uri.Host );
+                if (foundPos > 0) and (Length( uri.Host ) - foundPos + 1 = Length( BBS_HOST2 )) 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;
                        end;
                finally
                        uri.Free;
@@ -297,6 +323,67 @@ begin
 
 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;
 
 
 // =========================================================================
@@ -312,6 +399,7 @@ constructor TMachiBBSThreadItem.Create(
 var
        uri                                     : TIdURI;
        uriList                 : TStringList;
+       FilePath                : String;
 begin
 
        inherited;
@@ -319,12 +407,12 @@ begin
        OnDownload              := Download;
        OnWrite                         := Write;
        OnGetRes                        := GetRes;
-    OnGetDat                   := GetDat;
+       OnGetDat                        := GetDat;
        OnGetHeader             := GetHeader;
        OnGetFooter             := GetFooter;
        OnGetBoardURL   := GetBoardURL;
 
-       FilePath                        := '';
+       //FFilePath                     := '';
        FIsTemporary    := False;
        FDat                                    := nil;
        URL                                             := ReadURL + '&LAST=50';
@@ -366,23 +454,31 @@ end;
 // \8ew\92è\82µ\82½ URL \82Ì\83X\83\8c\83b\83h\82Ì\83_\83E\83\93\83\8d\81[\83h\82ð\8ew\8e¦\82³\82ê\82½
 // *************************************************************************
 function TMachiBBSThreadItem.Download : TDownloadState;
+const
+    RES_ERROR: String = '<ERROR>';
 var
        modified                        : Double;
        tmp                                             : PChar;
-       downResult              : TStringList;
+//     downResult              : TStringList;
        content                         : TStringList;
        responseCode    : Longint;
        logStream                       : TFileStream;
        uri                                             : TIdURI;
        uriList                         : TStringList;
        datURL                          : string;
-       foundPos                        : Integer;
+//     foundPos                        : Integer;
+       FilePath                        : String;
        procedure       downAndParse;
        begin
                responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
 
                try
                        if responseCode = 200 then begin
+                // API\82Å\82Ídat\8c`\8e®\82Å\95Ô\82Á\82Ä\82­\82é
+                content.Text := string( tmp );
+                if (content.Count > 0) and (Pos(RES_ERROR, content.Strings[0]) <> 1) then
+                    To2chDat2( content );   // \8c`\8e®\95Ï\8a·
+(* \8b\8c\8ed\97l\81iHTML\82Å\8eó\90M\82µdat\82É\95Ï\8a·\82·\82é\81j
                                downResult      := TStringList.Create;
                                try
                                        downResult.Text := string( tmp );
@@ -402,7 +498,6 @@ var
                                                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, Count + 1 );
@@ -411,6 +506,7 @@ var
                                finally
                                        downResult.Free;
                                end;
+*)
                        end else begin
                                Result := dsNotModify;
                                Exit;
@@ -446,52 +542,66 @@ begin
                // \93Æ\8e©\82É\83_\83E\83\93\83\8d\81[\83h\82â\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
                // InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
                modified        := LastModified;
+        // API\82ÌURL
+        datURL := uri.Protocol + '://' + uri.Host + '/bbs/offlaw.cgi/2/' +
+                    uriList.Values[ 'BBS' ] + '/' + uriList.Values[ 'KEY' ] + '/';
+               if (Count > 0) then
+            datURL := datURL + IntToStr( Count + 1 ) + '-';     // \90V\92\85\82Ì\82Ý\8eæ\93¾
+(* \8b\8c\8c`\8e®
                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
                downAndParse;
 
                if content.Count > 0 then begin
-                       if Count <= 0 then begin
-                               Result := dsComplete;
-                               // \90V\8bK\8f\91\82«\8d\9e\82Ý
-                               content[ 0 ]    := content[ 0 ] + Title;
-                               logStream                       := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
-                               try
-                                       logStream.Position      := logStream.Size;
-                                       logStream.Write( PChar( content.Text )^, Length( content.Text ) );
-                               finally
-                                       logStream.Free;
-                               end;
-                               NewReceive      := 1;
-                               Count                           := content.Count;
-                       end else 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;
-
-                       // 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;
+            if (Pos(RES_ERROR, content.Strings[0]) <> 1) then begin
+                if Count <= 0 then begin
+                    Result := dsComplete;
+                    // \90V\8bK\8f\91\82«\8d\9e\82Ý
+                    content[ 0 ]       := content[ 0 ] + Title;
+                    logStream                  := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
+                    try
+                        logStream.Position     := logStream.Size;
+                        logStream.Write( PChar( content.Text )^, Length( content.Text ) );
+                    finally
+                        logStream.Free;
+                    end;
+                    NewReceive := 1;
+                    Count                              := content.Count;
+                end else begin
+                    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;
+                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;
                end else begin
                        Result := dsNotModify;
                end;
@@ -537,7 +647,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
@@ -562,13 +672,13 @@ 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                        := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
+       res                     := FDat[ inNo - 1 ];
+       tmp                     := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
     try
                Result  := Dat2HTML( string( tmp ), inNo );
        finally
@@ -583,19 +693,25 @@ end;
 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     := '';
+       //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 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 := '';
+               tmp := CreateResultString('');
+               Result := tmp;
+               DisposeResultString(tmp);
                Exit;
        end;
-    try
-               Result := FDat[ inNo - 1 ];
-       except
-               Result := '';
+       tmp := CreateResultString(FDat[ inNo - 1]);
+       try
+               Result := string(tmp);
+       finally
+               DisposeResultString(tmp);
        end;
 
 end;
@@ -651,8 +767,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
@@ -665,15 +782,18 @@ begin
                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;
 
 end;
 
+(*
 // *************************************************************************
 // \82Ü\82¿BBS\82Ì HTML \82ð 2ch \82Ì dat \8c`\8e®\82É
 // *************************************************************************
@@ -683,7 +803,7 @@ procedure   TMachiBBSThreadItem.To2chDat(
 );
 var
        i, bound                        : Integer;
-       foundPos                        : Integer;
+       foundPos,foundPos2                      : Integer;
        strTmp                          : string;
        res                                             : TStringList;
        no                                              : Integer;
@@ -720,6 +840,7 @@ begin
                // \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É
     if AnsiPos('\81\9f</b>', ioHTML.Text) <> 0 then begin
        ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<b> </b></font>', '</b></font>', true );
@@ -744,6 +865,7 @@ begin
        try
                bound := ioHTML.Count - 1;
                for i := 0 to bound do begin
+            // \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ß
@@ -771,13 +893,94 @@ begin
                 end;
                        end;
                        ioHTML[ i ] := CustomStringReplace( res.Text, #13#10, '<>');
-                       //StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
+            // \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;
        end;
 
 end;
+*)
+
+// *************************************************************************
+// \82Ü\82¿BBS\82Ì dat \82ð 2ch \82Ì dat \8c`\8e®\82É
+// *************************************************************************
+procedure      TMachiBBSThreadItem.To2chDat2( var ioDat: TStringList );
+const
+    SEP_TAG: String = '<>';
+    ITEM_NUM:  Integer = 7;
+    IDX_HOST:  Integer = 6;
+    IDX_ID:    Integer = 3;
+    IDX_ADDST: Integer = 1;
+    IDX_ADDED: Integer = 5;
+    IDX_NO:    Integer = 0;
+var
+    DstTmp: TStringList;
+    ResLine: TStringList;
+    TmpLine: String;
+    i: Integer;
+    j: Integer;
+    Sep: Integer;
+    No: Integer;
+    GetNo: Integer;
+begin
+    DstTmp := TStringList.Create;
+    ResLine := TStringList.Create;
+    try
+        No := Count + 1;    // \8ds\94Ô\8d\86\81i\83\8c\83X\94Ô\8d\86\81j
+        for i := 0 to ioDat.Count - 1 do begin
+            // \82P\8ds\82ð\8d\80\96Ú\95Ê\82É\90Ø\82è\95ª\82¯\82é
+            ResLine.Clear;
+            TmpLine := ioDat.Strings[i];
+            while (True) do begin
+                Sep := Pos(SEP_TAG, TmpLine);
+                if (Sep > 0) then begin
+                    ResLine.Add(Copy(TmpLine, 1, Sep - 1));
+                    Delete(TmpLine, 1, Sep + 1);
+                end else begin
+                    ResLine.Add(TmpLine);
+                    Break;
+                end;
+            end;
+            while (ResLine.Count < ITEM_NUM) do
+                ResLine.Add('');    // \95s\91«\8d\80\96Ú\90\94\82¾\82¯\92Ç\89Á
+
+            // \83z\83X\83g\96¼\82ðID\82Ì\8cã\82ë\82É\92Ç\89Á
+            ResLine.Strings[IDX_ID] := ResLine.Strings[IDX_ID] + ' <font size=1>IP: ' + ResLine.Strings[IDX_HOST] + ' </font>';
+
+            // \95K\97v\8d\80\96Ú\82¾\82¯\8dÄ\8c\8b\8d\87
+            for j := IDX_ADDST to IDX_ADDED do begin
+                if (j = IDX_ADDST) then
+                    TmpLine := ResLine.Strings[j]
+                else
+                    TmpLine := TmpLine + SEP_TAG + ResLine.Strings[j];
+            end;
+
+            GetNo := StrToIntDef(ResLine.Strings[IDX_NO], 0);
+            while (GetNo > No) do begin
+                DstTmp.Add('');
+                Inc(No);
+            end;
+
+            DstTmp.Add(TmpLine);
+
+            Inc(No);
+        end;
+        ioDat.Clear;
+        ioDat.Assign(DstTmp);
+       finally
+        ResLine.Free;
+        DstTmp.Free;
+       end;
+end;
 
 // *************************************************************************
 // FDat \82Ì\90\90¬
@@ -816,6 +1019,8 @@ var
        uri                             : TIdURI;
        uriList         : TStringList;
        foundPos        : Integer;
+const
+    THREAD_MARK2= '/bbs/read.cgi';
 begin
 
        foundPos := AnsiPos( '?', URL );
@@ -831,7 +1036,26 @@ begin
                        uri.Free;
                        uriList.Free;
                end;
-       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;
 
@@ -890,6 +1114,7 @@ begin
        FilePath                        := '';
        FIsTemporary    := False;
        FDat                                    := nil;
+    Is2ch                      := False;
 
        uri                     := TIdURI.Create( SubjectURL );
        uriList := TStringList.Create;
@@ -937,6 +1162,7 @@ var
        responseCode    : Longint;
        uri                                             : TIdURI;
        uriList                         : TStringList;
+    dlURL           : String;
 begin
 
        Result := dsError;
@@ -954,7 +1180,9 @@ begin
        // \93Æ\8e©\82É\83_\83E\83\93\83\8d\81[\83h\82â\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
        // InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
        modified                        := LastModified;
-       responseCode    := InternalDownload( PChar( uri.URI ), modified, downResult );
+    dlURL       := SubjectURL2;
+//     responseCode    := InternalDownload( PChar( uri.URI ), modified, downResult );
+       responseCode    := InternalDownload( PChar( dlURL ), modified, downResult );
        try
                if responseCode = 200 then begin
                        try
@@ -973,6 +1201,8 @@ begin
                                ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
 
                                FDat.Text := string( downResult );
+                // \8c`\8e®\95Ï\8a·(Ver.2->Ver.1)
+                ChangeSubjectFormat(FDat);
                                // \95Û\91
                                FDat.SaveToFile( FilePath );
 
@@ -992,6 +1222,28 @@ begin
 
 end;
 
+procedure TMachiBBSBoardItem.ChangeSubjectFormat(var dat: TStringList);
+var
+    i: Integer;
+    sep: Integer;
+    tmp: String;
+begin
+    for i := 0 to dat.Count - 1 do begin
+        tmp := dat.Strings[i];
+        sep := Pos('<>', tmp);
+        if (sep > 0) then begin
+            Delete(tmp, 1, sep + 1);
+            sep := Pos('<>', tmp);
+            if (sep > 0) then begin
+                Delete(tmp, sep, 2);
+                Insert('.cgi,', tmp, sep);
+                dat.Strings[i] := tmp;
+            end;
+        end;
+    end;
+end;
+
+
 // *************************************************************************
 // \83X\83\8c\97§\82Ä\82ð\8ew\8e¦\82³\82ê\82½
 // *************************************************************************
@@ -1027,7 +1279,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
@@ -1142,6 +1394,22 @@ begin
 end;
 
 // *************************************************************************
+// \83X\83\8c\88ê\97\97\82Ì URL \82ð\8b\81\82ß\82é(Ver2)
+// *************************************************************************
+function       TMachiBBSBoardItem.SubjectURL2 : string;
+var
+       uri: TIdURI;
+begin
+
+       uri := TIdURI.Create( URL );
+       try
+        Result := uri.Protocol + '://' + uri.Host + '/bbs/offlaw.cgi/2' + uri.Path;
+       finally
+               uri.Free;
+       end;
+end;
+
+// *************************************************************************
 // TBoardItem \82ª\90\90¬\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSBoardItem \82ð\90\90¬\82·\82é)
 // *************************************************************************
 procedure BoardItemOnCreateOfTMachiBBSBoardItem(
@@ -1214,8 +1482,8 @@ end;
 
 exports
        OnVersionInfo,
-       OnAcceptURL;
-
+       OnAcceptURL,
+    OnExtractBoardURL;
 begin
 
        try