OSDN Git Service

This commit was manufactured by cvs2svn to create branch 'Bb62'.
[gikonavigoeson/gikonavi.git] / ItemDownload.pas
index a3eb5bc..b005725 100644 (file)
@@ -5,8 +5,8 @@ interface
 uses
        Windows, SysUtils, Classes, ComCtrls, Controls, Forms, IdHTTP,
        {HTTPApp,} YofUtils, IdGlobal, IdException, IdComponent, IniFiles, {DateUtils,}
-       GikoSystem, BoardGroup, MonaUtils, ExternalBoardManager, ExternalBoardPlugInMain,
-       Sort;
+       GikoSystem, BoardGroup, ExternalBoardManager, ExternalBoardPlugInMain,
+       Sort, SyncObjs;
 
 type
        TDownloadItem = class;
@@ -27,7 +27,17 @@ type
                FErrText: string;
        end;
 
-
+       TWorkData = record
+           //FWorkCS: TCriticalSection;
+               //IdHttp\82ÌOnWork\81AOnWorkBegin,OnWorkEnd\82Í\95Ê\82Ì\83X\83\8c\83b\83h\82©\82ç
+        //\8cÄ\82Î\82ê\82é\88×\81ASynchronize\82Å\93¯\8aú\82·\82é\95K\97v\82ª\82 \82é\81B
+               //\83N\83\8a\83e\83B\83J\83\8b\83Z\83N\83V\83\87\83\93\82Í\96³\82­\82Ä\82à\82½\82Ô\82ñ\95½\8bC\82¾\82¯\82Ç\97p\90S\82Ì\88×\81B by eggcake
+               FWorkCS: TCriticalSection;
+               FSender: TObject;
+               FAWorkMode: TWorkMode;
+               FAWorkCount: Integer;
+               FAWorkCountMax: Integer
+       end;
        TDownloadThread = class(TThread)
        private
                FIndy: TIdHttp;
@@ -43,6 +53,7 @@ type
                FOnDownloadEnd: TDownloadEndEvent;
                FOnDownloadMsg: TDownloadMsgEvent;
                FDownloadTitle: string;
+        FWorkData: TWorkData;
 
                procedure FireDownloadEnd;
                procedure FireDownloadMsg;
@@ -53,8 +64,13 @@ type
                function ParseCgiStatus(Content: string): TCgiStatus;
                function CgiDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime): Boolean;
                function DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
-               function DeleteStatusLine(Content: string): string;
-       protected
+               procedure DeleteStatusLine(Item: TDownloadItem);
+               procedure InitHttpClient(client: TIdHttp);
+               procedure ClearHttpClient(client: TIdHttp);
+               procedure FireWork;
+               procedure FireWorkBegin;
+               procedure FireWorkEnd;
+       protected
                procedure Execute; override;
        public
                property Item: TDownloadItem read FItem write FItem;
@@ -103,9 +119,14 @@ type
 
 implementation
 
+uses
+       Y_TextConverter, MojuUtils, HTMLCreate, ReplaceDataModule;
+
 constructor TDownloadThread.Create(CreateSuspended: Boolean);
 begin
        inherited Create(CreateSuspended);
+    FWorkData.FWorkCS := TCriticalSection.Create;
+
        FIndy := TIdHttp.Create(nil);
 
        FIndy.OnWorkBegin := WorkBegin;
@@ -115,14 +136,9 @@ end;
 
 destructor TDownloadThread.Destroy;
 begin
-    FIndy.Request.CustomHeaders.Clear;
-    FIndy.Request.RawHeaders.Clear;
-    FIndy.Request.Clear;
-    FIndy.Response.CustomHeaders.Clear;
-    FIndy.Response.RawHeaders.Clear;
-    FIndy.Response.Clear;
-    FIndy.ProxyParams.Clear;
+       ClearHttpClient(FIndy);
        FIndy.Free;
+    FWorkData.FWorkCS.Free;
        inherited;
 end;
 
@@ -143,7 +159,65 @@ begin
                                                                                [Day, Copy(StrMonth, 1 + 3 * (Month - 1), 3),
                                                                                 Year, Hour, Min, Sec]);
 end;
-
+// ******************************************************************
+// HTTPClient\82Ì\8f\89\8aú\89»
+// ******************************************************************
+procedure TDownloadThread.InitHttpClient(client: TIdHttp);
+begin
+       ClearHttpClient(client);
+       client.Disconnect;
+       client.Request.UserAgent := GikoSys.GetUserAgent;
+       client.RecvBufferSize := Gikosys.Setting.RecvBufferSize;
+       client.ProxyParams.BasicAuthentication := False;
+       client.ReadTimeout := GikoSys.Setting.ReadTimeOut;
+       {$IFDEF DEBUG}
+       Writeln('------------------------------------------------------------');
+       {$ENDIF}
+       //FIndy.AllowCookies := False;
+       if GikoSys.Setting.ReadProxy then begin
+               if GikoSys.Setting.ProxyProtocol then
+                       client.ProtocolVersion := pv1_1
+               else
+                       client.ProtocolVersion := pv1_0;
+               client.ProxyParams.ProxyServer := GikoSys.Setting.ReadProxyAddress;
+               client.ProxyParams.ProxyPort := GikoSys.Setting.ReadProxyPort;
+               client.ProxyParams.ProxyUsername := GikoSys.Setting.ReadProxyUserID;
+               client.ProxyParams.ProxyPassword := GikoSys.Setting.ReadProxyPassword;
+               if GikoSys.Setting.ReadProxyUserID <> '' then
+                       client.ProxyParams.BasicAuthentication := True;
+               {$IFDEF DEBUG}
+               Writeln('\83v\83\8d\83L\83V\90Ý\92è\82 \82è');
+               Writeln('\83z\83X\83g: ' + GikoSys.Setting.ReadProxyAddress);
+               Writeln('\83|\81[\83g: ' + IntToStr(GikoSys.Setting.ReadProxyPort));
+               {$ENDIF}
+       end else begin
+               if GikoSys.Setting.Protocol then
+                       client.ProtocolVersion := pv1_1
+               else
+                       client.ProtocolVersion := pv1_0;
+               client.ProxyParams.ProxyServer := '';
+               client.ProxyParams.ProxyPort := 80;
+               client.ProxyParams.ProxyUsername := '';
+               client.ProxyParams.ProxyPassword := '';
+               {$IFDEF DEBUG}
+               Writeln('\83v\83\8d\83L\83V\90Ý\92è\82È\82µ');
+               {$ENDIF}
+       end;
+end;
+// ******************************************************************
+// HTTPClient\82Ì\83\8a\83N\83G\83X\83g\82Æ\83\8c\83X\83|\83\93\83X\82Ì\83f\81[\83^\82Ì\8fÁ\8b\8e
+// ******************************************************************
+procedure TDownloadThread.ClearHttpClient(client: TIdHttp);
+begin
+       client.Request.CustomHeaders.Clear;
+       client.Request.RawHeaders.Clear;
+       client.Request.Clear;
+       client.Response.CustomHeaders.Clear;
+       client.Response.RawHeaders.Clear;
+       client.Response.Clear;
+
+       client.ProxyParams.Clear;
+end;
 procedure TDownloadThread.Execute;
 var
        ResStream: TMemoryStream;
@@ -187,10 +261,14 @@ begin
                        begin
                                FDownloadTitle := FItem.FThreadItem.Title;
                                if FItem.FThreadItem <> nil then begin
-                                       if FItem.FThreadItem.IsBoardPlugInAvailable then begin
-                                               boardPlugIn     := FItem.FThreadItem.BoardPlugIn;
+                                       if FItem.FThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
+                                               boardPlugIn := FItem.FThreadItem.ParentBoard.BoardPlugIn;
                                                Item.State      := TGikoDownloadState( boardPlugIn.DownloadThread( DWORD( FItem.FThreadItem ) ) );
                                        end;
+                                       //if FItem.FThreadItem.IsBoardPlugInAvailable then begin
+                                       //      boardPlugIn     := FItem.FThreadItem.BoardPlugIn;
+                                       //      Item.State      := TGikoDownloadState( boardPlugIn.DownloadThread( DWORD( FItem.FThreadItem ) ) );
+                                       //end;
                                end;
                        end;
                end;
@@ -210,51 +288,9 @@ begin
                        Continue;
                end;
 
-               //===== \83v\83\89\83O\83C\83\93\82ð\8eg\97p\82µ\82È\82¢\8fê\8d\87
                FAbort := False;
-               FIndy.Request.CustomHeaders.Clear;
-               FIndy.Response.Clear;
-               FIndy.Request.Clear;
-    FIndy.ProxyParams.Clear;
-    FIndy.Disconnect;
-               FIndy.Request.UserAgent := GikoSys.GetUserAgent;
-               FIndy.RecvBufferSize := Gikosys.Setting.RecvBufferSize;
-               FIndy.ProxyParams.BasicAuthentication := False;
-        FIndy.ReadTimeout := GikoSys.Setting.ReadTimeOut;
-               {$IFDEF DEBUG}
-               Writeln('------------------------------------------------------------');
-               {$ENDIF}
-               //FIndy.AllowCookies := False;
-               if GikoSys.Setting.ReadProxy then begin
-                       if GikoSys.Setting.ProxyProtocol then
-                               FIndy.ProtocolVersion := pv1_1
-                       else
-                               FIndy.ProtocolVersion := pv1_0;
-                       FIndy.ProxyParams.ProxyServer := GikoSys.Setting.ReadProxyAddress;
-                       FIndy.ProxyParams.ProxyPort := GikoSys.Setting.ReadProxyPort;
-                       FIndy.ProxyParams.ProxyUsername := GikoSys.Setting.ReadProxyUserID;
-                       FIndy.ProxyParams.ProxyPassword := GikoSys.Setting.ReadProxyPassword;
-                       if GikoSys.Setting.ReadProxyUserID <> '' then
-                               FIndy.ProxyParams.BasicAuthentication := True;
-                       {$IFDEF DEBUG}
-                       Writeln('\83v\83\8d\83L\83V\90Ý\92è\82 \82è');
-                       Writeln('\83z\83X\83g: ' + GikoSys.Setting.ReadProxyAddress);
-                       Writeln('\83|\81[\83g: ' + IntToStr(GikoSys.Setting.ReadProxyPort));
-                       {$ENDIF}
-               end else begin
-                       if GikoSys.Setting.Protocol then
-                               FIndy.ProtocolVersion := pv1_1
-                       else
-                               FIndy.ProtocolVersion := pv1_0;
-                       FIndy.ProxyParams.ProxyServer := '';
-                       FIndy.ProxyParams.ProxyPort := 80;
-                       FIndy.ProxyParams.ProxyUsername := '';
-                       FIndy.ProxyParams.ProxyPassword := '';
-                       {$IFDEF DEBUG}
-                       Writeln('\83v\83\8d\83L\83V\90Ý\92è\82È\82µ');
-                       {$ENDIF}
-               end;
-
+               //===== \83v\83\89\83O\83C\83\93\82ð\8eg\97p\82µ\82È\82¢\8fê\8d\87
+               InitHttpClient(FIndy);
                adjustMargin := 0;
                if Item.DownType = gdtThread then begin
                        if FileExists( Item.ThreadItem.GetThreadFileName ) then begin
@@ -356,9 +392,9 @@ begin
 
                                if Trim(FIndy.Response.RawHeaders.Values['Date']) <> '' then begin
                                        if Item.DownType = gdtBoard then
-                                               Item.Board.LastGetTime := MonaUtils.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date'])
+                                               Item.Board.LastGetTime := GikoSys.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date'])
                                        else
-                                               Item.ThreadItem.ParentBoard.LastGetTime := MonaUtils.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date']);
+                                               Item.ThreadItem.ParentBoard.LastGetTime := GikoSys.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date']);
                                end;
 
                                if DownloadResult then begin
@@ -427,6 +463,28 @@ begin
                                end;
 
                                //********************
+                               //dat.gz\81@\81¨\81@dat\82Ì\8eæ\93¾\81@2005\94N6\8c\8e\92Ç\89Á\81@by\82à\82\82ã
+                               //********************
+                               if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
+                                       {$IFDEF DEBUG}
+                                       Writeln('dat\8eæ\93¾');
+                                       {$ENDIF}
+                                       FMsg := '\89ß\8b\8e\83\8d\83O(dat.gz)\82ª\91\8dÝ\82µ\82È\82¢\82½\82ß\89ß\8b\8e\83\8d\83O(dat)\82ð\92T\82µ\82Ü\82· - [' + ATitle + ']';
+                                       FIcon := gmiWhat;
+                                       if Assigned(OnDownloadMsg) then
+                                               Synchronize(FireDownloadMsg);
+                                       URL := ChangeFileExt(URL, '');
+                                       Modified := Item.ThreadItem.LastModified;
+                                       RangeStart := 0;
+                                       AdjustLen := 0;
+                                       if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
+                                               Item.State := gdsError;
+                                       {$IFDEF DEBUG}
+                                       Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
+                                       {$ENDIF}
+                               end;
+
+                               //********************
                                //dat.gz\8eæ\93¾(2)
                                //********************
 {
@@ -491,8 +549,7 @@ begin
                                                                Writeln('CGIStatus: OK');
                                                                {$ENDIF}
                                                                Item.ResponseCode := 200;
-                                                               Item.Content := DeleteStatusLine(Item.Content);
-                                                               Item.ContentLength := CgiStatus.FSize;
+                                                               DeleteStatusLine(Item);
                                                        end;
                                                        gcsINCR: begin
                                                                //\8d¡\82Í\82 \82è\82¦\82È\82¢
@@ -500,8 +557,7 @@ begin
                                                                Writeln('CGIStatus: 206');
                                                                {$ENDIF}
                                                                Item.ResponseCode := 206;
-                                                               Item.Content := DeleteStatusLine(Item.Content);
-                                                               Item.ContentLength := CgiStatus.FSize;
+                                                               DeleteStatusLine(Item);
                                                        end;
                                                        gcsERR: begin
                                                                {$IFDEF DEBUG}
@@ -566,68 +622,9 @@ begin
                                        else
                                                Item.State := gdsError;
                                end;
-{
-                               //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
-                               if (Item.ResponseCode in [200, 206]) and (Item.Content = '') then
-                                       Item.State := gdsError;
-                               Item.LastModified := FIndy.Response.LastModified;
-                               //\8d·\95ª\8eæ\93¾\82Å\82P\83o\83C\83g\91O\82©\82ç\82Æ\82Á\82Ä\82«\82½\82Æ\82«\82Í\83}\83C\83i\83X\82·\82é
-                               Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
-                               try
-                                       ResStream.Clear;
-                                       FIndy.Get(URL, ResStream);
-                                       Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
-                                       if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] <> #10) then begin
-                                               //\8d·\95ª\8eæ\93¾\82©\82Â\82P\83o\83C\83g\96Ú\82ªLF\82Å\82È\82¢\8fê\8d\87\82Í\81u\82 \82Ú\81[\82ñ\81v\82³\82ê\82Ä\82¢\82é\82©\82à\82µ\82ê\82ñ\82Ì\82Å\8dÄ\8eæ\93¾
-                                               //\82±\82±\82Å\83\81\83b\83Z\81[\83W\95\\8e¦\83C\83x\83\93\83g
-                                               //event
-                                               FMsg := '\81u\82 \82Ú\81[\82ñ\81v\82ð\8c\9f\8fo\82µ\82½\82Ì\82Å\8dÄ\8eæ\93¾\82ð\8ds\82¢\82Ü\82·';
-                                               if Assigned(OnDownloadMsg) then
-                                                       Synchronize(FireDownloadMsg);
-                                               FIndy.Request.ContentRangeStart := 0;
-                                               FIndy.Request.ContentRangeEnd := 0;
-                                               AdjustLen := 0;
-                                               ResStream.Clear;
-                                               FIndy.Get(URL, ResStream);
-                                               Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
-                                       end else if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] = #10) then begin
-                                               //\8d·\95ª\8eæ\93¾\82©\82Â\82P\83o\83C\83g\96Ú\82ªLF\82Ì\8fê\8d\87\81i\90³\8fí\8eæ\93¾\81j\82Í\93ª\82ÌLF\82ð\8dí\8f\9c
-                                               Item.Content := Copy(Item.Content, 2, Length(Item.Content));
-                                       end;
-                               except
-                                       Item.State := gdsError;
-                               end;
-                               Item.ResponseCode := FIndy.ResponseCode;
-}
-{
-                               try
-                                       ResStream.Clear;
-                                       FIndy.Get(URL, ResStream);
-                                       Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
-                               except
-                                       Item.State := gdsError;
-                               end;
-
-                               CgiStatus := ParseCgiStatus(Item.Content);
-                               if CgiStatus.FStatus = gcsOK then begin
-                                       if CgiStatus.FSize = 0 then
-                                               Item.State := gdsNotModify
-                                       else if Item.DownType = gdtBoard then
-                                               Item.State := gdsComplete
-                                       else
-                                               Item.State := gdsDiffComplete;
-                               end else if CgiStatus.FStatus = gcsINCR then begin
-                                       Item.State := gdsComplete;
-                               end else if CgiStatus.FStatus = gcsERR then begin
-                                       Item.State := gdsError;
-                                       Item.ErrText := CgiStatus.FErrText;
-                               end;
-                               Item.ContentLength := CgiStatus.FSize;
-                               }
                        except
                                Item.State := gdsError;
                        end;
-                       //Item.ResponseCode := FIndy.ResponseCode;
                        if FAbort then
                                Item.State := gdsAbort;
                finally
@@ -636,13 +633,7 @@ begin
                        ResStream.Free;
                end;
 
-               FIndy.Request.CustomHeaders.Clear;
-        FIndy.Request.RawHeaders.Clear;
-        FIndy.Request.Clear;
-        FIndy.Response.CustomHeaders.Clear;
-        FIndy.Response.RawHeaders.Clear;
-               FIndy.Response.Clear;
-           FIndy.ProxyParams.Clear;
+               ClearHttpClient(FIndy);
 
                if Terminated then Break;
                Suspend;
@@ -734,8 +725,6 @@ var
 begin
        ResponseCode := -1;
        if (ItemType = gdtThread) and (RangeStart > 0) then begin
-//     if (ItemType = gdtThread) and (Item.ThreadItem.Size > 0) then begin
-//             FIndy.Request.ContentRangeStart := Item.ThreadItem.Size + AdjustLen;
                FIndy.Request.ContentRangeStart := RangeStart + AdjustLen;
                FIndy.Request.ContentRangeEnd := 0;
        end else begin
@@ -748,9 +737,7 @@ begin
        FIndy.Request.CustomHeaders.Add('Pragma: no-cache');
        if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
                FIndy.Request.LastModified := modified - OffsetFromUTC;
-               //FIndy.Request.CustomHeaders.Add('If-Modified-Since: ' + RFC1123_Date(modified - OffsetFromUTC) + ' GMT');
        end;
-//     FIndy.Request.AcceptEncoding := 'gzip';
        if RangeStart = 0 then
                FIndy.Request.AcceptEncoding := 'gzip'
        else
@@ -763,14 +750,13 @@ begin
                        Writeln('URL: ' + URL);
                        {$ENDIF}
                        FIndy.Get(URL, ResStream);
-                       Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
-                       Item.LastModified := FIndy.Response.LastModified;
-                       //\8d·\95ª\8eæ\93¾\82Å\82P\83o\83C\83g\91O\82©\82ç\82Æ\82Á\82Ä\82«\82½\82Æ\82«\82Í\83}\83C\83i\83X\82·\82é
-//                     Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
+            Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
                        Item.ContentLength := Length(Item.Content) + AdjustLen;
-                       //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
-//                     if (FIndy.ResponseCode in [200, 206]) and (Item.Content = '') then
-//                             Result := False
+            // \92u\8a·\82·\82é
+            if GikoSys.Setting.ReplaceDat then begin
+                Item.Content := ReplaceDM.Replace(Item.Content);
+            end;
+                       Item.LastModified := FIndy.Response.LastModified;
                        if Item.Content = '' then
                                Result := False
                        else
@@ -845,22 +831,72 @@ begin
        end;
 end;
 
-procedure TDownloadThread.WorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
+procedure TDownloadThread.WorkBegin(Sender: TObject;
+AWorkMode: TWorkMode; const AWorkCountMax: Integer);
 begin
-       if Assigned(OnWorkBegin) then
-               OnWorkBegin(Sender, AWorkMode, AWorkCountMax, FNumber, FDownloadTitle);
+       if Assigned(OnWorkBegin) then begin
+               FWorkData.FWorkCS.Acquire;
+               try
+                       FWorkData.FSender := Sender;
+                       FWorkData.FAWorkMode := AWorkMode;
+                       FWorkData.FAWorkCountMax := AWorkCountMax;
+                       Synchronize(FireWorkBegin);
+               finally
+                       FWorkData.FWorkCS.Release;
+               end;
+       end;
 end;
 
-procedure TDownloadThread.WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
+procedure TDownloadThread.WorkEnd(Sender: TObject;
+AWorkMode: TWorkMode);
 begin
-       if Assigned(OnWorkEnd) then
-               OnWorkEnd(Sender, AWorkMode, FNumber);
+       if Assigned(OnWorkEnd) then begin;
+               FWorkData.FWorkCS.Acquire;
+               try
+                       FWorkData.FSender := Sender;
+                       FWorkData.FAWorkMode := AWorkMode;
+                       Synchronize(FireWorkEnd);
+               finally
+                       FWorkData.FWorkCS.Release;
+               end;
+       end;
 end;
 
-procedure TDownloadThread.Work(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
+procedure TDownloadThread.Work(Sender: TObject; AWorkMode:
+TWorkMode; const AWorkCount: Integer);
 begin
-       if Assigned(OnWork) then
-               OnWork(Sender, AWorkMode, AWorkCount, FNumber);
+       if Assigned(OnWork) then begin
+               FWorkData.FWorkCS.Acquire;
+               try
+                       FWorkData.FSender := Sender;
+                       FWorkData.FAWorkMode := AWorkMode;
+                       FWorkData.FAWorkCount := AWorkCount;
+                       Synchronize(FireWork);
+               finally
+                       FWorkData.FWorkCS.Release;
+               end;
+       end;
+end;
+
+//\82±\82±\82©\82ç\90V\8bK\83\81\83\\83b\83h
+procedure TDownloadThread.FireWorkBegin;
+begin
+       OnWorkBegin(FWorkData.FSender, FWorkData.FAWorkMode,
+        FWorkData.FAWorkCountMax,
+               FNumber, FDownloadTitle);
+end;
+
+procedure TDownloadThread.FireWorkEnd;
+begin
+       OnWorkEnd(FWorkData.FSender, FWorkData.FAWorkMode,
+               FNumber);
+end;
+
+procedure TDownloadThread.FireWork;
+begin
+       OnWork(FWorkData.FSender, FWorkData.FAWorkMode,
+        FWorkData.FAWorkCount,
+               FNumber);
 end;
 
 function TDownloadThread.ParseCgiStatus(Content: string): TCgiStatus;
@@ -919,17 +955,20 @@ begin
        end;
 end;
 
-//\8eè\94²\82«\82È\8f\88\97\9d\82Å1\8ds\96Ú\82ð\8fÁ\82·
-function TDownloadThread.DeleteStatusLine(Content: string): string;
+//\82P\8ds\96Ú\82ð\8fÁ\82µ\82Ä\81A\83R\83\93\83e\83\93\83c\83T\83C\83Y\82ð\90Ý\92è\82·\82é
+procedure TDownloadThread.DeleteStatusLine(Item: TDownloadItem);
 var
        SList: TStringList;
 begin
        SList := TStringList.Create;
        try
-               SList.Text := Content;
+               SList.Text := Item.Content;
+               //1\8ds\96Ú\82ð\8dí\8f\9c
                if SList.Count > 1 then
                        SList.Delete(0);
-               Result := SList.Text;
+        Item.Content := SList.Text;
+               //\89ü\8ds\83R\81[\83h\82ðCRLF -> LF\82Æ\8dl\82¦\82Ä\81A\8ds\90\94\95ª\82¾\82¯\83}\83C\83i\83X
+        Item.ContentLength := Length(SList.Text) - SList.Count;
        finally
                SList.Free;
        end;
@@ -943,6 +982,9 @@ var
        NumCount: Integer;
        Body: TStringList;
        Rec: TSubjectRec;
+       {$IFDEF DEBUG}
+       st, rt : Cardinal;
+       {$ENDIF}
        function MakeThreadCallBack(
                inInstance      : DWORD;        // TBoardItem \82Ì\83C\83\93\83X\83^\83\93\83X
                inURL                           : PChar;        // \83X\83\8c\83b\83h\82Ì URL
@@ -957,10 +999,13 @@ var
                boardItem       := TBoard( inInstance );
 
                boardItem.IntData := boardItem.IntData + 1;
-               index := boardItem.GetIndexFromURL( string( inURL ) );
+               if boardItem.IntData < (boardItem.Count shr      2) then
+                       index := boardItem.GetIndexFromURL( string( inURL ) )
+               else
+                       index := boardItem.GetIndexFromURL( string( inURL ), True );
                if index = -1 then begin
                        //\90V\82µ\82¢\83X\83\8c\83b\83h
-                       _ThreadItem := TThreadItem.Create( boardItem.BoardPlugIn, string( inURL ) );
+                       _ThreadItem := TThreadItem.Create( boardItem.BoardPlugIn, boardItem, string( inURL ) );
 
                        _ThreadItem.Title                                       := string( inTitle );
                        _ThreadItem.AllResCount         := inCount;
@@ -971,18 +1016,26 @@ var
                        _ThreadItem.AgeSage                             := gasNew;
                        boardItem.Add(_ThreadItem);
                end else begin
+                       //\8f\87\88Ê\82ª\8fã\82ª\82Á\82Ä\82¢\82ê\82ÎAge\82É\82·\82é
                        if boardItem.Items[index].No > boardItem.IntData then
                                boardItem.Items[index].AgeSage := gasAge
-                       else if boardItem.Items[index].AllResCount < inCount then
+                       //\8f\87\88Ê\82ª\8fã\82ª\82Á\82Ä\82È\82¢\82¯\82Ç\81A\83\8c\83X\82ª\82Â\82¢\82Ä\82½\82ç\81ASage\82É
+                       else if boardItem.Items[index].AllResCount <> inCount then
                                boardItem.Items[index].AgeSage := gasSage
+                       //\8f\87\88Ê\8fã\82ª\82Á\82Ä\82È\82¢\82µ\81A\83\8c\83X\82Ì\91\9d\8c¸\82à\96³\82¯\82ê\82Î\81ANone
                        else
                                boardItem.Items[index].AgeSage := gasNone;
 
                        boardItem.Items[index].No                                               := boardItem.IntData;
                        boardItem.Items[index].AllResCount      := inCount;
                end;
+
        end;
 begin
+{$IFDEF DEBUG}
+       st := GetTickCount;
+       Writeln('SAVELIST');
+{$ENDIF}
        //Board.ListData := TList.Create;
        Body := TStringList.Create;
        try
@@ -991,15 +1044,21 @@ begin
                //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
                Board.LastModified := LastModified;
 
+
                //dat\97\8e\82¿\83X\83\8c\82Ì\83\\81[\83g\8f\87\82ð\8c\88\92è\82·\82é\82½\82ß\82É\83\\81[\83g\82·\82é
                if GikoSys.Setting.DatOchiSortIndex >= 0 then begin
-                       Sort.SortNoFlag := true;
-                       Sort.SortOrder := GikoSys.Setting.DatOchiSortOrder;
-                       Sort.SortIndex := GikoSys.Setting.DatOchiSortIndex;
+                       Sort.SetSortNoFlag(true);
+                       Sort.SetSortOrder(GikoSys.Setting.DatOchiSortOrder);
+                       Sort.SetSortIndex(GikoSys.Setting.DatOchiSortIndex);
                        //Sort.SortNonAcquiredCountFlag := GikoSys.Setting.NonAcquiredCount;
                        Board.CustomSort(ThreadItemSortProc);
                end;
 
+{$IFDEF DEBUG}
+       rt := GetTickCount - st;
+       Writeln('END Sortd' + IntToStr(rt) + ' ms');
+{$ENDIF}
+
                for i := Board.Count - 1 downto 0 do
                        Board.Items[i].AgeSage := gasNull;
 
@@ -1008,9 +1067,22 @@ begin
                        // \90V\82µ\82¢\83\8a\83X\83g\82É\8cÃ\82¢\83\8a\83X\83g\82Ì\83\8d\83O\82ª\82 \82é\82È\82ç\82»\82ê\82ð\90V\82µ\82¢\83\8a\83X\83g\82É\92Ç\89Á
                        // \8cÃ\82¢\83\8d\83O\82ª\82È\82¯\82ê\82Î\81A\90V\82½\82É\83X\83\8c\83I\83u\83W\83F\83N\83g\82ð\8dì\90¬
                        Board.IntData := 0;
+{$IFDEF DEBUG}
+       rt := GetTickCount - st;
+       Writeln('Start Enum' + IntToStr(rt) + ' ms');
+{$ENDIF}
+
+                       //\82±\82ê\82ª\92x\82¢\81@\97v\89ü\91P
+                       Board.BeginUpdate;
                        Board.BoardPlugIn.EnumThread( DWORD( Board ), @MakeThreadCallBack );
+                       Board.EndUpdate;
 
-            //\8cÃ\82¢\83\8a\83X\83g\82É\82µ\82©\82È\82¢\82â\82Â\82ç\82ð\8dí\8f\9c
+{$IFDEF DEBUG}
+       rt := GetTickCount - st;
+       Writeln('End Enum' + IntToStr(rt) + ' ms');
+{$ENDIF}
+
+                       //\8cÃ\82¢\83\8a\83X\83g\82É\82µ\82©\82È\82¢\82â\82Â\82ç\82ð\8dí\8f\9c
                        for i := Board.Count - 1 downto 0 do begin
                                if( Board.Items[i].AgeSage = gasNull )and not (Board.Items[i].IsLogFile) then
                                        Board.Delete(i);
@@ -1023,9 +1095,10 @@ begin
                                        Board.Items[i].No                                               := Board.IntData;
                                        Board.Items[i].AllResCount      := Board.Items[i].Count;
                                        Board.Items[i].NewResCount      := 0;
-                                       Board.Items[i].AgeSage                  := gasNone;
+                                       Board.Items[i].AgeSage                  := gasArch;
                                end;
                        end;
+
                end else begin
                        //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
                        //\90V\82µ\82¢\83\8a\83X\83g\82É\8cÃ\82¢\83\8a\83X\83g\82Ì\83\8d\83O\82ª\82 \82é\82È\82ç\82»\82ê\82ð\90V\82µ\82¢\83\8a\83X\83g\82É\92Ç\89Á
@@ -1041,7 +1114,9 @@ begin
                                if index = -1 then begin
                                        //\90V\82µ\82¢\83X\83\8c\83b\83h
                                        NewItem := TThreadItem.Create(
-                       nil, GikoSys.Get2chBoard2ThreadURL( Board, ChangeFileExt( Rec.FFileName, '' ) ) );
+                                                               nil,
+                                Board,
+                                GikoSys.Get2chBoard2ThreadURL( Board, ChangeFileExt( Rec.FFileName, '' ) ) );
                                        NewItem.Title := Rec.FTitle;
                                        NewItem.AllResCount := Rec.FCount;
                                        NewItem.ParentBoard := Board;
@@ -1075,11 +1150,12 @@ begin
                                        Board.Items[i].No := NumCount;
                                        Board.Items[i].AllResCount := Board.Items[i].Count;
                                        Board.Items[i].NewResCount := 0;
-                                       Board.Items[i].AgeSage := gasNone;
+                                       Board.Items[i].AgeSage := gasArch;
                                end;
                        end;
                        //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
                        GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
+            Body.Text := MojuUtils.Sanitize(Body.Text);
                        Body.SaveToFile(Board.GetSubjectFileName);
                end;
        finally
@@ -1185,16 +1261,12 @@ var
        NewRes: Integer;
        finish : Boolean;
        loopCnt : Integer;
-//     KokoTxt : string;
-//     KokoIdx : Integer;
-//     NewTxt  : string;
-//     NewIdx  : Integer;
-//     LastTxt : string;
        LastIdx : Integer;
 begin
        FileName := ThreadItem.GetThreadFileName;
 
-       if not ThreadItem.IsBoardPlugInAvailable then begin
+       //if not ThreadItem.IsBoardPlugInAvailable then begin
+    if not ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
                if Trim(Content) = '' then
                        Exit;
 
@@ -1263,6 +1335,13 @@ begin
                                                if OldCnt >= Body.Count then OldCnt := Body.Count - 1;
                                                NewRes := Body.Count - OldCnt;
 
+                                               // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾\82ª\90V\92\85\83\8c\83X\94Ô\82ð\92´\82³\82È\82¢\82æ\82¤\82É(\88Ù\8fí\8fI\97¹\8e\9e\82Ì\83\8a\83J\83o\83\8a)
+                                               if ThreadItem.Kokomade > OldCnt then begin
+                                                       if OldCnt > 0 then
+                                                               ThreadItem.Kokomade := OldCnt
+                                                       else
+                                                               ThreadItem.Kokomade := 1;
+                                               end;
 
                                        finally
                                                oldBody.Free;
@@ -1280,7 +1359,7 @@ begin
                                Body.SaveToFile(FileName);
 
                                if ThreadItem.Title = '' then begin
-                                       Res := GikoSys.DivideStrLine(Body[0]);
+                                       THTMLCreate.DivideStrLine(Body[0], @Res);
                                        ThreadItem.Title := Res.FTitle;
                                end;
                                ThreadItem.Size := 0;
@@ -1302,7 +1381,6 @@ begin
        ThreadItem.RoundDate := Now;
        if not ThreadItem.UnRead then begin
                ThreadItem.UnRead := True;
-               ThreadItem.ParentBoard.UnRead := ThreadItem.ParentBoard.UnRead + 1;
        end;
 //     if ThreadItem.RoundNo = 6 then
 //             ThreadItem.RoundNo := 0;
@@ -1320,7 +1398,7 @@ begin
                ini.WriteInteger('Setting', 'NewResCount', ThreadItem.NewResCount);
                ini.WriteInteger('Setting', 'NewReceive', ThreadItem.NewReceive);
 //             ini.WriteInteger('Setting', 'RoundNo', ThreadItem.RoundNo);
-               ini.WriteBool('Setting', 'Round', ThreadItem.Round);
+//             ini.WriteBool('Setting', 'Round', ThreadItem.Round);
                ini.WriteBool('Setting', 'UnRead', ThreadItem.UnRead);
                ini.UpdateFile;
        finally