OSDN Git Service

1.64.1.820
[gikonavigoeson/gikonavi.git] / ItemDownload.pas
1 unit ItemDownload;
2
3 interface
4
5 uses
6         Windows, SysUtils, Classes, ComCtrls, Controls, Forms, IdHTTP,
7         {HTTPApp,} YofUtils, IdGlobal, IdException, IdComponent, IniFiles, {DateUtils,}
8         GikoSystem, BoardGroup, ExternalBoardManager, ExternalBoardPlugInMain,
9         Sort, SyncObjs;
10
11 type
12         TDownloadItem = class;
13         TGikoDownloadType = (gdtBoard, gdtThread);
14         TGikoDownloadState = (gdsWait, gdsWork, gdsComplete, gdsDiffComplete, gdsNotModify, gdsAbort, gdsError);
15         TGikoCgiStatus = (gcsOK, gcsINCR, gcsERR);
16         TGikoDLProgress = (gdpStd, gdpAll, gdpDatOchi, gdpOfflaw);
17
18         TGikoWorkEvent = procedure(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer; ID: Integer) of object;
19         TGikoWorkBeginEvent = procedure(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer; ID: Integer; const AWorkTitle: string) of object;
20         TGikoWorkEndEvent = procedure(Sender: TObject; AWorkMode: TWorkMode; ID: Integer) of object;
21         TDownloadEndEvent = procedure(Sender: TObject; Item: TDownloadItem) of object;
22         TDownloadMsgEvent = procedure(Sender: TObject; Item: TDownloadItem; Msg: string; Icon: TGikoMessageIcon) of object;
23
24         TCgiStatus = record
25                 FStatus: TGikoCgiStatus;
26                 FSize: Integer;
27                 FErrText: string;
28         end;
29
30         TWorkData = record
31             //FWorkCS: TCriticalSection;
32                 //IdHttp\82ÌOnWork\81AOnWorkBegin,OnWorkEnd\82Í\95Ê\82Ì\83X\83\8c\83b\83h\82©\82ç
33         //\8cÄ\82Î\82ê\82é\88×\81ASynchronize\82Å\93¯\8aú\82·\82é\95K\97v\82ª\82 \82é\81B
34                 //\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
35                 FWorkCS: TCriticalSection;
36                 FSender: TObject;
37                 FAWorkMode: TWorkMode;
38                 FAWorkCount: Integer;
39                 FAWorkCountMax: Integer
40         end;
41         TDownloadThread = class(TThread)
42         private
43                 FIndy: TIdHttp;
44                 FItem: TDownloadItem;
45                 FNumber: Integer;
46                 FAbort: Boolean;
47                 FMsg: string;
48                 FIcon: TGikoMessageIcon;
49                 FSessionID: string;
50                 FOnWork: TGikoWorkEvent;
51                 FOnWorkBegin: TGikoWorkBeginEvent;
52                 FOnWorkEnd: TGikoWorkEndEvent;
53                 FOnDownloadEnd: TDownloadEndEvent;
54                 FOnDownloadMsg: TDownloadMsgEvent;
55                 FDownloadTitle: string;
56         FWorkData: TWorkData;
57
58                 procedure FireDownloadEnd;
59                 procedure FireDownloadMsg;
60                 procedure GetSessionID;
61                 procedure WorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
62                 procedure WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
63                 procedure Work(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
64                 function ParseCgiStatus(Content: string): TCgiStatus;
65         function ParseRokkaStatus(Content: string): TCgiStatus;
66                 function CgiDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime): Boolean;
67                 function DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
68                 procedure DeleteStatusLine(Item: TDownloadItem);
69                 procedure InitHttpClient(client: TIdHttp);
70                 procedure ClearHttpClient(client: TIdHttp);
71                 procedure FireWork;
72                 procedure FireWorkBegin;
73                 procedure FireWorkEnd;
74         protected
75                 procedure Execute; override;
76         public
77                 property Item: TDownloadItem read FItem write FItem;
78                 property Number: Integer read FNumber write FNumber;
79                 constructor Create(CreateSuspended: Boolean);
80                                 destructor Destroy; override;
81                 procedure Abort;
82                 property OnWork: TGikoWorkEvent read FOnWork write FOnWork;
83                 property OnWorkBegin: TGikoWorkBeginEvent read FOnWorkBegin write FOnWorkBegin;
84                 property OnWorkEnd: TGikoWorkEndEvent read FOnWorkEnd write FOnWorkEnd;
85                 property OnDownloadEnd: TDownloadEndEvent read FOnDownloadEnd write FOnDownloadEnd;
86                 property OnDownloadMsg: TDownloadMsgEvent read FOnDownloadMsg write FOnDownloadMsg;
87         end;
88
89         TDownloadItem = class(TObject)
90         private
91                 FDownType: TGikoDownloadType;
92                 FBoard: TBoard;
93                 FThreadItem: TThreadItem;
94
95                 FContentLength: Integer;
96                 FLastModified: TDateTime;
97                 FContent: string;
98                 FResponseCode: Smallint;
99                 FState: TGikoDownloadState;
100                 FErrText: string;
101                 FForceDownload: Boolean;
102                 FIsAbone : Boolean;
103         public
104                 procedure SaveListFile;
105                 procedure SaveItemFile;
106
107                 property DownType: TGikoDownloadType read FDownType write FDownType;
108                 property Board: TBoard read FBoard write FBoard;
109                 property ThreadItem: TThreadItem read FThreadItem write FThreadItem;
110
111                 property ContentLength: Integer read FContentLength write FContentLength;
112                 property LastModified: TDateTime read FLastModified write FLastModified;
113                 property Content: string read FContent write FContent;
114                 property ResponseCode: Smallint read FResponseCode write FResponseCode;
115                 property State: TGikoDownloadState read FState write FState;
116                 property ErrText: string read FErrText write FErrText;
117                 property ForceDownload: Boolean read FForceDownload write FForceDownload;
118                 property IsAbone : Boolean read FIsAbone write FIsAbone;
119         end;
120
121 implementation
122
123 uses
124         Y_TextConverter, MojuUtils, HTMLCreate, ReplaceDataModule;
125
126 constructor TDownloadThread.Create(CreateSuspended: Boolean);
127 begin
128         inherited Create(CreateSuspended);
129     FWorkData.FWorkCS := TCriticalSection.Create;
130
131         FIndy := TIdHttp.Create(nil);
132
133         FIndy.OnWorkBegin := WorkBegin;
134         FIndy.OnWorkEnd := WorkEnd;
135         FIndy.OnWork := Work;
136 end;
137
138 destructor TDownloadThread.Destroy;
139 begin
140         ClearHttpClient(FIndy);
141         FIndy.Free;
142     FWorkData.FWorkCS.Free;
143         inherited;
144 end;
145
146 function RFC1123_Date(aDate : TDateTime) : String;
147 const
148          StrWeekDay : String = 'MonTueWedThuFriSatSun';
149          StrMonth        : String = 'JanFebMarAprMayJunJulAugSepOctNovDec';
150 var
151          Year, Month, Day                        : Word;
152          Hour, Min,      Sec, MSec : Word;
153          DayOfWeek                                                      : Word;
154 begin
155          DecodeDate(aDate, Year, Month, Day);
156          DecodeTime(aDate, Hour, Min,    Sec, MSec);
157          DayOfWeek := ((Trunc(aDate) - 2) mod 7);
158          Result := Copy(StrWeekDay, 1 + DayOfWeek * 3, 3) + ', ' +
159                                                  Format('%2.2d %s %4.4d %2.2d:%2.2d:%2.2d',
160                                                                                 [Day, Copy(StrMonth, 1 + 3 * (Month - 1), 3),
161                                                                                  Year, Hour, Min, Sec]);
162 end;
163 // ******************************************************************
164 // HTTPClient\82Ì\8f\89\8aú\89»
165 // ******************************************************************
166 procedure TDownloadThread.InitHttpClient(client: TIdHttp);
167 begin
168         ClearHttpClient(client);
169         client.Disconnect;
170         client.Request.UserAgent := GikoSys.GetUserAgent;
171         client.RecvBufferSize := Gikosys.Setting.RecvBufferSize;
172         client.ProxyParams.BasicAuthentication := False;
173         client.ReadTimeout := GikoSys.Setting.ReadTimeOut;
174         {$IFDEF DEBUG}
175         Writeln('------------------------------------------------------------');
176         {$ENDIF}
177         //FIndy.AllowCookies := False;
178         if GikoSys.Setting.ReadProxy then begin
179                 if GikoSys.Setting.ProxyProtocol then
180                         client.ProtocolVersion := pv1_1
181                 else
182                         client.ProtocolVersion := pv1_0;
183                 client.ProxyParams.ProxyServer := GikoSys.Setting.ReadProxyAddress;
184                 client.ProxyParams.ProxyPort := GikoSys.Setting.ReadProxyPort;
185                 client.ProxyParams.ProxyUsername := GikoSys.Setting.ReadProxyUserID;
186                 client.ProxyParams.ProxyPassword := GikoSys.Setting.ReadProxyPassword;
187                 if GikoSys.Setting.ReadProxyUserID <> '' then
188                         client.ProxyParams.BasicAuthentication := True;
189                 {$IFDEF DEBUG}
190                 Writeln('\83v\83\8d\83L\83V\90Ý\92è\82 \82è');
191                 Writeln('\83z\83X\83g: ' + GikoSys.Setting.ReadProxyAddress);
192                 Writeln('\83|\81[\83g: ' + IntToStr(GikoSys.Setting.ReadProxyPort));
193                 {$ENDIF}
194         end else begin
195                 if GikoSys.Setting.Protocol then
196                         client.ProtocolVersion := pv1_1
197                 else
198                         client.ProtocolVersion := pv1_0;
199                 client.ProxyParams.ProxyServer := '';
200                 client.ProxyParams.ProxyPort := 80;
201                 client.ProxyParams.ProxyUsername := '';
202                 client.ProxyParams.ProxyPassword := '';
203                 {$IFDEF DEBUG}
204                 Writeln('\83v\83\8d\83L\83V\90Ý\92è\82È\82µ');
205                 {$ENDIF}
206         end;
207 end;
208 // ******************************************************************
209 // HTTPClient\82Ì\83\8a\83N\83G\83X\83g\82Æ\83\8c\83X\83|\83\93\83X\82Ì\83f\81[\83^\82Ì\8fÁ\8b\8e
210 // ******************************************************************
211 procedure TDownloadThread.ClearHttpClient(client: TIdHttp);
212 begin
213         client.Request.CustomHeaders.Clear;
214         client.Request.RawHeaders.Clear;
215         client.Request.Clear;
216         client.Response.CustomHeaders.Clear;
217         client.Response.RawHeaders.Clear;
218         client.Response.Clear;
219
220         client.ProxyParams.Clear;
221 end;
222 procedure TDownloadThread.Execute;
223 var
224         ResStream: TMemoryStream;
225
226         URL: string;
227         CgiStatus: TCgiStatus;
228         Modified: TDateTime;
229         RangeStart: Integer;
230         AdjustLen: Integer;
231         Idx: Integer;
232         ATitle: string;
233         DownloadResult: Boolean;
234         boardPlugIn     : TBoardPlugIn;
235         lastContent             : string;
236         logFile                         : TFileStream;
237         adjustMargin    : Integer;
238 const
239         ADJUST_MARGIN   = 16;
240 begin
241         while not Terminated do begin
242                 //===== \83v\83\89\83O\83C\83\93
243                 FAbort := False;
244                 boardPlugIn := nil;
245                 ExternalBoardManager.OnWork                             := Work;
246                 ExternalBoardManager.OnWorkBegin        := WorkBegin;
247                 ExternalBoardManager.OnWorkEnd          := WorkEnd;
248
249                 FDownloadTitle := '';
250                 case FItem.FDownType of
251                 gdtBoard:
252                         begin
253                                 FDownloadTitle := FItem.FBoard.Title;
254                                 if FItem.FBoard <> nil then begin
255                                         if FItem.FBoard.IsBoardPlugInAvailable then begin
256                                                 boardPlugIn     := FItem.FBoard.BoardPlugIn;
257                                                 Item.State      := TGikoDownloadState( boardPlugIn.DownloadBoard( DWORD( FItem.FBoard ) ) );
258                                         end;
259                                 end;
260                         end;
261                 gdtThread:
262                         begin
263                                 FDownloadTitle := FItem.FThreadItem.Title;
264                                 if FItem.FThreadItem <> nil then begin
265                                         if FItem.FThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
266                                                 boardPlugIn := FItem.FThreadItem.ParentBoard.BoardPlugIn;
267                                                 Item.State      := TGikoDownloadState( boardPlugIn.DownloadThread( DWORD( FItem.FThreadItem ) ) );
268                                         end;
269                                         //if FItem.FThreadItem.IsBoardPlugInAvailable then begin
270                                         //      boardPlugIn     := FItem.FThreadItem.BoardPlugIn;
271                                         //      Item.State      := TGikoDownloadState( boardPlugIn.DownloadThread( DWORD( FItem.FThreadItem ) ) );
272                                         //end;
273                                 end;
274                         end;
275                 end;
276                 if Length(FDownloadTitle) = 0 then
277                         FDownloadTitle := '\81i\96¼\8fÌ\95s\96¾\81j';
278
279                 if boardPlugIn <> nil then begin
280                         if FAbort then begin
281                                 Item.State := gdsAbort;
282                         end;
283                         if Assigned( OnDownloadEnd ) then
284                                 Synchronize( FireDownloadEnd );
285                         if Terminated then
286                                 Break;
287
288                         Suspend;
289                         Continue;
290                 end;
291
292                 FAbort := False;
293                 //===== \83v\83\89\83O\83C\83\93\82ð\8eg\97p\82µ\82È\82¢\8fê\8d\87
294                 InitHttpClient(FIndy);
295                 adjustMargin := 0;
296                 if Item.DownType = gdtThread then begin
297                         if FileExists( Item.ThreadItem.GetThreadFileName ) then begin
298                                 // dat \83t\83@\83C\83\8b\82Ì\8dÅ\8cã\82ð\93Ç\82Ý\8fo\82·
299                                 SetLength( lastContent, ADJUST_MARGIN + 1 );
300                                 logFile := TFileStream.Create( Item.ThreadItem.GetThreadFileName, fmOpenRead or fmShareDenyWrite );
301                                 try
302                                         logFile.Seek( -(ADJUST_MARGIN + 1), soFromEnd );
303                                         logFile.Read( lastContent[ 1 ], ADJUST_MARGIN + 1 );
304                                         lastContent := StringReplace( lastContent, #13, '', [] );       // CR \82Ì\8dí\8f\9c
305                                 finally
306                                         logFile.Free;
307                                 end;
308                         end else begin
309         lastContent := '';
310                         end;
311                         adjustMargin := Length( lastContent );
312                 end;
313
314                 FIndy.Request.ContentRangeStart := 0;
315                 FIndy.Request.LastModified := ZERO_DATE;
316                 ResStream := TMemoryStream.Create;
317                 try
318                         try
319                                 //********************
320                                 //DAT or Subject\8eæ\93¾
321                                 //********************
322                                 Item.ResponseCode := 0;
323                                 RangeStart := 0;
324                                 AdjustLen := 0;
325                                 Modified := 0;
326                                 if Item.DownType = gdtBoard then begin
327                                         {$IFDEF DEBUG}
328                                         Writeln('Subject\8eæ\93¾');
329                                         Writeln('URL: ' + Item.Board.GetReadCgiURL);
330                                         Writeln('Modified: ' + FloatToStr(Item.Board.LastModified));
331                                         {$ENDIF}
332                                         URL := Item.Board.GetReadCgiURL;
333                                         if Item.ForceDownload then begin
334                                                 // \8b­\90§\8eæ\93¾
335                                                 ATitle := Item.Board.Title;
336                                                 if ATitle = '' then
337                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
338                                                 FMsg := '\81\9a\8b­\90§\8eæ\93¾\82ð\8ds\82¢\82Ü\82· - [' + ATitle + ']';
339                                                 FIcon := gmiWhat;
340                                                 if Assigned(OnDownloadMsg) then
341                                                         Synchronize(FireDownloadMsg);
342                                                 Modified := ZERO_DATE
343                                         end else begin
344                                                 Modified := Item.Board.LastModified;
345                                         end;
346                                 end else if Item.DownType = gdtThread then begin
347                                         {$IFDEF DEBUG}
348                                         Writeln('DAT\8eæ\93¾');
349                                         Writeln('URL: ' + Item.ThreadItem.GetDatURL);
350                                         Writeln('Modified: ' + FloatToStr(Item.ThreadItem.LastModified));
351                                         {$ENDIF}
352                                         URL := Item.ThreadItem.GetDatURL;
353                                         if Item.ForceDownload then begin
354                                                 // \8b­\90§\8eæ\93¾
355                                                 ATitle := Item.ThreadItem.Title;
356                                                 if ATitle = '' then
357                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
358                                                 FMsg := '\81\9a\8b­\90§\8eæ\93¾\82ð\8ds\82¢\82Ü\82· - [' + ATitle + ']';
359                                                 FIcon := gmiWhat;
360                                                 if FileExists(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG')) = true then
361                                                         DeleteFile(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG'));
362                                                 if Assigned(OnDownloadMsg) then
363                                                         Synchronize(FireDownloadMsg);
364                                                 Modified := ZERO_DATE;
365                                                 RangeStart := 0;
366                                                 AdjustLen := 0;
367                                         end else begin
368                                                 Modified := Item.ThreadItem.LastModified;
369                                                 if Item.ThreadItem.Size > 0 then begin
370                                                         {$IFDEF DEBUG}
371                                                         Writeln('RangeStart: ' + IntToStr(Item.ThreadItem.Size));
372                                                         {$ENDIF}
373                                                         // \82 \82Ú\81[\82ñ\83`\83F\83b\83N\82Ì\82½\82ß adjustMargin \83o\83C\83g\91O\82©\82ç\8eæ\93¾
374                                                         RangeStart := Item.ThreadItem.Size;
375                                                         AdjustLen := -adjustMargin;
376                                                 end;
377                                         end;
378                                 end;
379                                 Item.IsAbone := False;
380                                 DownloadResult := DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen);
381                                 {$IFDEF DEBUG}
382                                 Writeln('ResponseCode: ' + IntToStr(FIndy.ResponseCode));
383                                 {$ENDIF}
384                                 if Item.DownType = gdtThread then begin
385                                         if Item.ResponseCode = 416 then begin
386                                                 Item.IsAbone := True;
387                                                 DownloadResult := True;
388                                         end else if DownloadResult and (AdjustLen < 0) then begin
389                                                 if Copy( Item.Content, 1, adjustMargin ) <> lastContent then
390                                                         Item.IsAbone := True;
391                                         end;
392                                 end;
393
394                                 if Trim(FIndy.Response.RawHeaders.Values['Date']) <> '' then begin
395                                         if Item.DownType = gdtBoard then
396                                                 Item.Board.LastGetTime := GikoSys.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date'])
397                                         else
398                                                 Item.ThreadItem.ParentBoard.LastGetTime := GikoSys.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date']);
399                                 end;
400
401                                 if DownloadResult then begin
402                                         {$IFDEF DEBUG}
403                                         Writeln('Date:' + FIndy.Response.RawHeaders.Values['Date']);
404                                         {$ENDIF}
405                                         if Item.IsAbone then begin
406                                                 {$IFDEF DEBUG}
407                                                 Writeln('\82 \82Ú\81[\82ñ\8c\9f\8fo');
408                                                 {$ENDIF}
409                                                 ATitle := Item.ThreadItem.Title;
410                                                 if ATitle = '' then
411                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
412                                                 //\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¾
413                                                 RangeStart := 0;
414                                                 AdjustLen := 0;
415                                                 FMsg := '\81\9a\81u\82 \82Ú\81[\82ñ\81v\82ð\8c\9f\8fo\82µ\82½\82Ì\82Å\8dÄ\8eæ\93¾\82ð\8ds\82¢\82Ü\82· - [' + ATitle + ']';
416                                                 FIcon := gmiWhat;
417                                                 if FileExists(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG')) = true then
418                                                         DeleteFile(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG'));
419                                                 if Assigned(OnDownloadMsg) then
420                                                         Synchronize(FireDownloadMsg);
421                                                 if not DatDownload(Item.DownType, URL, ZERO_DATE, RangeStart, AdjustLen) then
422                                                         Item.State := gdsError;
423                                                 {$IFDEF DEBUG}
424                                                 Writeln('\82 \82Ú\81[\82ñ\8dÄ\8eæ\93¾\8cã');
425                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
426                                                 {$ENDIF}
427                                         end else if (Item.DownType = gdtThread) and (AdjustLen < 0) then begin
428                                                 // \8d·\95ª\8eæ\93¾\82ª\8fo\97\88\82½\8fê\8d\87\82Í\82 \82Ú\81[\82ñ\83`\83F\83b\83N\97p\82É\8eæ\93¾\82µ\82½\97]\95ª\82È\83T\83C\83Y\82ð\8dí\8f\9c
429                                                 Item.Content := Copy(Item.Content, adjustMargin + 1, MaxInt);
430                                         end;
431                                 end else begin
432                                         Item.State := gdsError;
433                                         if (Item.DownType = gdtBoard) and (Item.ResponseCode = 302) then begin
434                                                 FMsg := '\81\9a\81\9a\94Â\82ª\88Ú\93]\82µ\82½\82©\82à\82µ\82ê\82È\82¢\82Ì\82Å\94Â\8dX\90V\82ð\8ds\82Á\82Ä\82­\82¾\82³\82¢\81\9a\81\9a';
435                                                 FIcon := gmiNG;
436                                                 if Assigned(OnDownloadMsg) then
437                                                         Synchronize(FireDownloadMsg);
438                                         end;
439                                 end;
440
441                                 //********************
442                                 //dat.gz\8eæ\93¾(1)
443                                 //********************
444                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
445                                         {$IFDEF DEBUG}
446                                         Writeln('dat.gz\8eæ\93¾');
447                                         {$ENDIF}
448                                         ATitle := Item.ThreadItem.Title;
449                                         if ATitle = '' then
450                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
451                                         FMsg := '\81\9adat\82ª\91\8dÝ\82µ\82È\82¢\82½\82ß\89ß\8b\8e\83\8d\83O(dat.gz)\82ð\92T\82µ\82Ü\82· - [' + ATitle + ']';
452                                         FIcon := gmiWhat;
453                                         if Assigned(OnDownloadMsg) then
454                                                 Synchronize(FireDownloadMsg);
455                                         URL := Item.ThreadItem.GetDatgzURL;
456                                         Modified := Item.ThreadItem.LastModified;
457                                         RangeStart := 0;
458                                         AdjustLen := 0;
459                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
460                                                 Item.State := gdsError;
461                                         {$IFDEF DEBUG}
462                                         Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
463                                         {$ENDIF}
464                                 end;
465
466                                 //********************
467                                 //dat.gz\81@\81¨\81@dat\82Ì\8eæ\93¾\81@2005\94N6\8c\8e\92Ç\89Á\81@by\82à\82\82ã
468                                 //********************
469                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
470                                         {$IFDEF DEBUG}
471                                         Writeln('dat\8eæ\93¾');
472                                         {$ENDIF}
473                                         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 + ']';
474                                         FIcon := gmiWhat;
475                                         if Assigned(OnDownloadMsg) then
476                                                 Synchronize(FireDownloadMsg);
477                                         URL := ChangeFileExt(URL, '');
478                                         Modified := Item.ThreadItem.LastModified;
479                                         RangeStart := 0;
480                                         AdjustLen := 0;
481                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
482                                                 Item.State := gdsError;
483                                         {$IFDEF DEBUG}
484                                         Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
485                                         {$ENDIF}
486                                 end;
487
488                                 //********************
489                                 //dat.gz\8eæ\93¾(2)
490                                 //********************
491 {
492                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
493                                         ATitle := Item.ThreadItem.Title;
494                                         if ATitle = '' then
495                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
496                                         FMsg := '\81\9a\89ß\8b\8e\83\8d\83O(1)\82ª\91\8dÝ\82µ\82È\82¢\82½\82ß\89ß\8b\8e\83\8d\83O(2)\82©\82ç\92T\82µ\82Ü\82· - [' + ATitle + ']';
497                                         FIcon := gmiWhat;
498                                         if Assigned(OnDownloadMsg) then
499                                                 Synchronize(FireDownloadMsg);
500                                         URL := Item.ThreadItem.GetOldDatgzURL;
501                                         Modified := Item.ThreadItem.LastModified;
502                                         RangeStart := 0;
503                                         AdjustLen := 0;
504                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
505                                                 Item.State := gdsError;
506                                 end;
507 }
508
509 //////////////// 2013/10/13 ShiroKuma\91Î\89\9e zako Start ///////////////////////////
510                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
511                                         {$IFDEF DEBUG}
512                                         Writeln('offlaw2.so\82Å\8eæ\93¾');
513                                         {$ENDIF}
514                                         ATitle := Item.ThreadItem.Title;
515                                         if ATitle = '' then
516                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
517                                         FMsg := '\81\9adat.gz\82ª\91\8dÝ\82µ\82È\82¢\82½\82ßofflaw2.so\82ð\97\98\97p\82µ\82Ü\82· - [' + ATitle + ']';
518                                         FIcon := gmiWhat;
519                                         if Assigned(OnDownloadMsg) then
520                                                 Synchronize(FireDownloadMsg);
521                                         URL := Item.ThreadItem.GetOfflaw2SoURL;
522                                         Modified := Item.ThreadItem.LastModified;
523                                         RangeStart := 0;
524                                         AdjustLen := 0;
525                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then begin
526                                                 {$IFDEF DEBUG}
527                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
528                                                 {$ENDIF}
529                                                 Item.State := gdsError;
530
531                                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
532                                                         FMsg := '\94Â\82ª\88Ú\93]\82µ\82½\82©\82à\82µ\82ê\82È\82¢\82Ì\82Å\94Â\8dX\90V\82ð\8ds\82Á\82Ä\82­\82¾\82³\82¢\81B';
533                                                         FIcon := gmiNG;
534                                                         if Assigned(OnDownloadMsg) then
535                                                                 Synchronize(FireDownloadMsg);
536                                                 end;
537
538                                         end else begin
539                                                 {$IFDEF DEBUG}
540                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
541                                                 {$ENDIF}
542                                                 if Item.ResponseCode = 200 then begin
543                                                         {$IFDEF DEBUG}
544                                                         Writeln('CGIStatus: OK');
545                                                         {$ENDIF}
546                             if Copy(Item.Content, 1, 5) = 'ERROR' then begin
547                                 {$IFDEF DEBUG}
548                                 Writeln('Offlow2Error');
549                                 {$ENDIF}
550                                 Item.ResponseCode := 404;
551                                 Item.State := gdsError;
552                                 Item.ErrText := '\83X\83\8c\82Í\91\8dÝ\82µ\82È\82¢\82æ\82¤\82Å\82·\81B' + Item.Content;
553                             end;
554                                                 end else begin
555                                                         {$IFDEF DEBUG}
556                                                         Writeln('CGIStatus: 404(ERROR)');
557                                                         {$ENDIF}
558                                                         Item.ResponseCode := 404;
559                                                         Item.State := gdsError;
560                                                         Item.ErrText := CgiStatus.FErrText;
561                                                 end;
562                                         end;
563                                 end;
564 //////////////// 2013/10/13 ShiroKuma\91Î\89\9e zako End /////////////////////////////
565
566 //////////////// 2014/03/08 Rokka\91Î\89\9e zako Start ///////////////////////////////
567                                 if (Item.DownType = gdtThread) and ((Item.ResponseCode = 302) or (Item.ResponseCode = 404)) then begin
568                                 FSessionID := '';
569                                 Synchronize(GetSessionID);
570                     if (FSessionID <> '') then begin
571                         {$IFDEF DEBUG}
572                         Writeln('Rokka\82Å\8eæ\93¾');
573                         {$ENDIF}
574                         ATitle := Item.ThreadItem.Title;
575                         if ATitle = '' then
576                             ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
577                         FMsg := '\81\9aofflow2.so\82É\91\8dÝ\82µ\82È\82¢\82½\82ßRokka\82ð\97\98\97p\82µ\82Ü\82· - [' + ATitle + ']';
578                         FIcon := gmiWhat;
579                         if Assigned(OnDownloadMsg) then
580                             Synchronize(FireDownloadMsg);
581                         URL := Item.ThreadItem.GetRokkaURL(FSessionID);
582                         Modified := Item.ThreadItem.LastModified;
583                         RangeStart := 0;
584                         AdjustLen := 0;
585
586                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then begin
587                             {$IFDEF DEBUG}
588                             Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
589                             {$ENDIF}
590                             Item.State := gdsError;
591                         end else begin
592                             CgiStatus := ParseRokkaStatus(Item.Content);
593                             {$IFDEF DEBUG}
594                             Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
595                             {$ENDIF}
596                             case CgiStatus.FStatus of
597                                 gcsOK: begin
598                                     {$IFDEF DEBUG}
599                                     Writeln('CGIStatus: OK');
600                                     {$ENDIF}
601                                     Item.ResponseCode := 200;
602                                     DeleteStatusLine(Item);
603                                 end;
604                                 gcsERR: begin
605                                     {$IFDEF DEBUG}
606                                     Writeln('CGIStatus: 404(ERROR)');
607                                     {$ENDIF}
608                                     Item.ResponseCode := 404;
609                                     Item.State := gdsError;
610                                     Item.ErrText := CgiStatus.FErrText;
611                                 end;
612                             end;
613                         end;
614                     end;
615                                 end;
616 //////////////// 2014/03/08 Rokka\91Î\89\9e zako End /////////////////////////////////
617
618                                 //********************
619                                 //VIP\83T\81[\83r\83X\89ß\8b\8e\83\8d\83O\91Î\89\9e
620                                 //********************
621                                 if (AnsiPos('vip2ch.com', GikoSys.UrlToServer(URL)) > 0) and (Item.DownType = gdtThread) and (Item.ResponseCode = 404) then begin
622                                         {$IFDEF DEBUG}
623                                         Writeln('VIP\83T\81[\83r\83X\89ß\8b\8e\83\8d\83O\8eæ\93¾');
624                                         {$ENDIF}
625                                         URL := Item.ThreadItem.GetVIPServiceKakoDatURL;
626                                         Modified := Item.ThreadItem.LastModified;
627                                         RangeStart := 0;
628                                         AdjustLen := 0;
629                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
630                                                 Item.State := gdsError;
631                                         {$IFDEF DEBUG}
632                                         Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
633                                         {$ENDIF}
634                                 end;
635
636                                 //********************
637                                 //offlaw.cgi\82Å\8eæ\93¾
638                                 //********************
639                                 FSessionID := '';
640                                 Synchronize(GetSessionID);
641                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID <> '') then begin
642                                         {$IFDEF DEBUG}
643                                         Writeln('offlaw.cgi\82Å\8eæ\93¾');
644                                         {$ENDIF}
645                                         ATitle := Item.ThreadItem.Title;
646                                         if ATitle = '' then
647                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
648                                         FMsg := '\81\9adat.gz\82ª\91\8dÝ\82µ\82È\82¢\82½\82ßofflaw.cgi\82ð\97\98\97p\82µ\82Ü\82· - [' + ATitle + ']';
649                                         FIcon := gmiWhat;
650                                         if Assigned(OnDownloadMsg) then
651                                                 Synchronize(FireDownloadMsg);
652                                         URL := Item.ThreadItem.GetOfflawCgiURL(FSessionID);
653                                         Modified := Item.ThreadItem.LastModified;
654                                         RangeStart := 0;
655                                         AdjustLen := 0;
656                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then begin
657                                                 {$IFDEF DEBUG}
658                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
659                                                 {$ENDIF}
660                                                 Item.State := gdsError;
661
662                                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
663                                                         FMsg := '\94Â\82ª\88Ú\93]\82µ\82½\82©\82à\82µ\82ê\82È\82¢\82Ì\82Å\94Â\8dX\90V\82ð\8ds\82Á\82Ä\82­\82¾\82³\82¢\81B';
664                                                         FIcon := gmiNG;
665                                                         if Assigned(OnDownloadMsg) then
666                                                                 Synchronize(FireDownloadMsg);
667                                                 end;
668
669                                         end else begin
670                                                 CgiStatus := ParseCgiStatus(Item.Content);
671                                                 {$IFDEF DEBUG}
672                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
673                                                 {$ENDIF}
674                                                 case CgiStatus.FStatus of
675                                                         gcsOK: begin
676                                                                 {$IFDEF DEBUG}
677                                                                 Writeln('CGIStatus: OK');
678                                                                 {$ENDIF}
679                                                                 Item.ResponseCode := 200;
680                                                                 DeleteStatusLine(Item);
681                                                         end;
682                                                         gcsINCR: begin
683                                                                 //\8d¡\82Í\82 \82è\82¦\82È\82¢
684                                                                 {$IFDEF DEBUG}
685                                                                 Writeln('CGIStatus: 206');
686                                                                 {$ENDIF}
687                                                                 Item.ResponseCode := 206;
688                                                                 DeleteStatusLine(Item);
689                                                         end;
690                                                         gcsERR: begin
691                                                                 {$IFDEF DEBUG}
692                                                                 Writeln('CGIStatus: 404(ERROR)');
693                                                                 {$ENDIF}
694                                                                 Item.ResponseCode := 404;
695                                                                 Item.State := gdsError;
696                                                                 Item.ErrText := CgiStatus.FErrText;
697                                                         end;
698                                                 end;
699                                                 if (Item.ResponseCode = 404) and (AnsiPos('\89ß\8b\8e\83\8d\83O\91q\8cÉ\82Å\94­\8c©', Item.ErrText) <> 0) then begin
700                                                         {$IFDEF DEBUG}
701                                                         Writeln('\89ß\8b\8e\83\8d\83O\8eæ\93¾');
702                                                         {$ENDIF}
703                                                         ATitle := Item.ThreadItem.Title;
704                                                         if ATitle = '' then
705                                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
706                                                         FMsg := '\81\9a\89ß\8b\8e\83\8d\83O\91q\8cÉ\82Å\94­\8c© - [' + ATitle + ']';
707                                                         FIcon := gmiWhat;
708                                                         if Assigned(OnDownloadMsg) then
709                                                                 Synchronize(FireDownloadMsg);
710                                                         Idx := Pos(' ', Item.ErrText);
711                                                         if Idx <> 0 then begin
712                                                                 URL := Copy(Item.ErrText, Idx + 1, Length(Item.ErrText));
713                                                                 if Pos( '://', URL ) = 0 then begin
714                                                                         if Pos('../', URL) = 1 then
715                                                                                 URL := Copy(URL, 4, MaxInt );
716                                                                         if Pos( '/', URL ) = 1 then
717                                                                                 URL := Copy( URL, 2, MaxInt );
718                                                                         URL := GikoSys.UrlToServer(Item.ThreadItem.ParentBoard.URL) + URL;
719                                                                 end;
720                                                                 Modified := Item.ThreadItem.LastModified;
721                                                                 RangeStart := 0;
722                                                                 AdjustLen := 0;
723                                                                 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
724                                                                         Item.State := gdsError;
725                                                                 {$IFDEF DEBUG}
726                                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
727                                                                 {$ENDIF}
728                                                         end;
729                                                 end;
730                                         end;
731                                 end else begin
732                                         if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID = '') then begin
733                                                 {$IFDEF DEBUG}
734                                                 Writeln('\83\8d\83O\83C\83\93\82³\82ê\82Ä\82È\82¢\82Ì\82Å\89ß\8b\8e\83\8d\83O\8eæ\93¾\95s\89Â');
735                                                 {$ENDIF}
736                                                 ATitle := Item.ThreadItem.Title;
737                                                 if ATitle = '' then
738                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
739                                                 FMsg := '\81\9a\83\8d\83O\83C\83\93\82³\82ê\82Ä\82¢\82È\82¢\82½\82ß\92T\82·\82±\82Æ\82ª\8fo\97\88\82Ü\82¹\82ñ - [' + ATitle + ']';
740                                                 FIcon := gmiSAD;
741                                                 if Assigned(OnDownloadMsg) then
742                                                         Synchronize(FireDownloadMsg);
743                                         end;
744                                 end;
745
746                                 case Item.ResponseCode of
747                                         200: Item.State := gdsComplete;
748                                         206: Item.State := gdsDiffComplete;
749                                         304: Item.State := gdsNotModify;
750                                         else
751                                                 Item.State := gdsError;
752                                 end;
753                         except
754                                 Item.State := gdsError;
755                         end;
756                         if FAbort then
757                                 Item.State := gdsAbort;
758                 finally
759                         if Assigned(OnDownloadEnd) then
760                                 Synchronize(FireDownloadEnd);
761                         ResStream.Free;
762                 end;
763
764                 ClearHttpClient(FIndy);
765
766                 if Terminated then Break;
767                 Suspend;
768         end;
769 end;
770
771 function TDownloadThread.CgiDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime): Boolean;
772 var
773         ResponseCode: Integer;
774         ResStream: TMemoryStream;
775 begin
776         ResponseCode := -1;
777         FIndy.Request.ContentRangeStart := 0;
778         FIndy.Request.ContentRangeEnd := 0;
779
780         FIndy.Request.CustomHeaders.Clear;
781         if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
782                 FIndy.Request.LastModified := modified - OffsetFromUTC;
783         end;
784         FIndy.Request.AcceptEncoding := '';
785         FIndy.Request.Accept := 'text/html';
786         ResStream := TMemoryStream.Create;
787         try
788                 try
789                         ResStream.Clear;
790                         {$IFDEF DEBUG}
791                         Writeln('URL: ' + URL);
792                         {$ENDIF}
793                         FIndy.Get(URL, ResStream);
794                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
795                         Item.LastModified := FIndy.Response.LastModified;
796                         //\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é
797                         Item.ContentLength := Length(Item.Content);
798                         //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
799                         if Item.Content = '' then
800                                 Result := False
801                         else
802                                 Result := True;
803                         {$IFDEF DEBUG}
804                         Writeln('\8eæ\93¾\82Å\97á\8aO\82È\82µ');
805                         {$ENDIF}
806                         ResponseCode := FIndy.ResponseCode;
807                 except
808                         on E: EIdSocketError do begin
809                                 Item.Content := '';
810                                 Item.LastModified := ZERO_DATE;
811                                 Item.ContentLength := 0;
812                                 Item.ErrText := E.Message;
813                                 Result := False;
814                                 ResponseCode := -1;
815                                 Screen.Cursor := crDefault;
816                         end;
817                         on E: EIdConnectException do begin
818                                 Item.Content := '';
819                                 Item.LastModified := ZERO_DATE;
820                                 Item.ContentLength := 0;
821                                 Item.ErrText := E.Message;
822                                 Result := False;
823                                 ResponseCode := -1;
824                                 Screen.Cursor := crDefault;
825                         end;
826                         on E: Exception do begin
827                                 {$IFDEF DEBUG}
828                                 Writeln('\8eæ\93¾\82Å\97á\8aO\82 \82è');
829                                 Writeln('E.Message: ' + E.Message);
830                                 {$ENDIF}
831                                 Item.Content := '';
832                                 Item.LastModified := ZERO_DATE;
833                                 Item.ContentLength := 0;
834                                 Item.ErrText := E.Message;
835                                 ResponseCode := FIndy.ResponseCode;
836                                 Result := False;
837                                 Screen.Cursor := crDefault;
838                         end;
839                 end;
840         finally
841                 if (Item.ContentLength = 0) and (ResponseCode = 206) then
842                         Item.ResponseCode := 304
843                 else
844                         Item.ResponseCode := ResponseCode;
845                 ResStream.Free;
846         end;
847 end;
848
849 function TDownloadThread.DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
850 var
851         ResponseCode: Integer;
852         ResStream: TMemoryStream;
853 begin
854         ResponseCode := -1;
855         if (ItemType = gdtThread) and (RangeStart > 0) then begin
856                 FIndy.Request.ContentRangeStart := RangeStart + AdjustLen;
857                 FIndy.Request.ContentRangeEnd := 0;
858         end else begin
859                 FIndy.Request.ContentRangeStart := 0;
860                 FIndy.Request.ContentRangeEnd := 0;
861         end;
862
863         FIndy.Request.CustomHeaders.Clear;
864         FIndy.Request.CacheControl := 'no-cache';
865         FIndy.Request.CustomHeaders.Add('Pragma: no-cache');
866         if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
867                 FIndy.Request.LastModified := modified - OffsetFromUTC;
868         end;
869         if RangeStart = 0 then
870                 FIndy.Request.AcceptEncoding := 'gzip'
871         else
872                 FIndy.Request.AcceptEncoding := '';
873         ResStream := TMemoryStream.Create;
874         try
875                 try
876                         ResStream.Clear;
877                         {$IFDEF DEBUG}
878                         Writeln('URL: ' + URL);
879                         {$ENDIF}
880                         FIndy.Get(URL, ResStream);
881             Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
882                         Item.ContentLength := Length(Item.Content) + AdjustLen;
883             // \92u\8a·\82·\82é
884             if GikoSys.Setting.ReplaceDat then begin
885                 Item.Content := ReplaceDM.Replace(Item.Content);
886             end;
887                         Item.LastModified := FIndy.Response.LastModified;
888                         if Item.Content = '' then
889                                 Result := False
890                         else
891                                 Result := True;
892                         {$IFDEF DEBUG}
893                         Writeln('\8eæ\93¾\82Å\97á\8aO\82È\82µ');
894                         {$ENDIF}
895                         ResponseCode := FIndy.ResponseCode;
896                 except
897                         on E: EIdSocketError do begin
898                                 Item.Content := '';
899                                 Item.LastModified := ZERO_DATE;
900                                 Item.ContentLength := 0;
901                                 Item.ErrText := E.Message;
902                                 Result := False;
903                                 ResponseCode := -1;
904                                 Screen.Cursor := crDefault;
905                         end;
906                         on E: EIdConnectException do begin
907                                 Item.Content := '';
908                                 Item.LastModified := ZERO_DATE;
909                                 Item.ContentLength := 0;
910                                 Item.ErrText := E.Message;
911                                 Result := False;
912                                 ResponseCode := -1;
913                                 Screen.Cursor := crDefault;
914                         end;
915                         on E: Exception do begin
916                                 {$IFDEF DEBUG}
917                                 Writeln('\8eæ\93¾\82Å\97á\8aO\82 \82è');
918                                 Writeln('E.Message: ' + E.Message);
919                                 {$ENDIF}
920                                 Item.Content := '';
921                                 Item.LastModified := ZERO_DATE;
922                                 Item.ContentLength := 0;
923                                 Item.ErrText := E.Message;
924                                 ResponseCode := FIndy.ResponseCode;
925                                 Result := False;
926                                 Screen.Cursor := crDefault;
927                         end;
928                 end;
929         finally
930                 if (Item.ContentLength = 0) and (ResponseCode = 206) then
931                         Item.ResponseCode := 304
932                 else
933                         Item.ResponseCode := ResponseCode;
934                 ResStream.Free;
935         end;
936 end;
937
938 procedure TDownloadThread.FireDownloadEnd;
939 begin
940         OnDownloadEnd(self, Item);
941 end;
942
943 procedure TDownloadThread.FireDownloadMsg;
944 begin
945         OnDownloadMsg(Self, Item, FMsg, FIcon);
946 end;
947
948 procedure TDownloadThread.GetSessionID;
949 begin
950         FSessionID := GikoSys.Dolib.SessionID;
951 end;
952
953 procedure TDownloadThread.Abort;
954 begin
955         FAbort := True;
956         FIndy.DisconnectSocket;
957         if socket <> nil then begin
958                 socket.DisconnectSocket;
959         end;
960 end;
961
962 procedure TDownloadThread.WorkBegin(Sender: TObject;
963 AWorkMode: TWorkMode; const AWorkCountMax: Integer);
964 begin
965         if Assigned(OnWorkBegin) then begin
966                 FWorkData.FWorkCS.Acquire;
967                 try
968                         FWorkData.FSender := Sender;
969                         FWorkData.FAWorkMode := AWorkMode;
970                         FWorkData.FAWorkCountMax := AWorkCountMax;
971                         Synchronize(FireWorkBegin);
972                 finally
973                         FWorkData.FWorkCS.Release;
974                 end;
975         end;
976 end;
977
978 procedure TDownloadThread.WorkEnd(Sender: TObject;
979 AWorkMode: TWorkMode);
980 begin
981         if Assigned(OnWorkEnd) then begin;
982                 FWorkData.FWorkCS.Acquire;
983                 try
984                         FWorkData.FSender := Sender;
985                         FWorkData.FAWorkMode := AWorkMode;
986                         Synchronize(FireWorkEnd);
987                 finally
988                         FWorkData.FWorkCS.Release;
989                 end;
990         end;
991 end;
992
993 procedure TDownloadThread.Work(Sender: TObject; AWorkMode:
994 TWorkMode; const AWorkCount: Integer);
995 begin
996         if Assigned(OnWork) then begin
997                 FWorkData.FWorkCS.Acquire;
998                 try
999                         FWorkData.FSender := Sender;
1000                         FWorkData.FAWorkMode := AWorkMode;
1001                         FWorkData.FAWorkCount := AWorkCount;
1002                         Synchronize(FireWork);
1003                 finally
1004                         FWorkData.FWorkCS.Release;
1005                 end;
1006         end;
1007 end;
1008
1009 //\82±\82±\82©\82ç\90V\8bK\83\81\83\\83b\83h
1010 procedure TDownloadThread.FireWorkBegin;
1011 begin
1012         OnWorkBegin(FWorkData.FSender, FWorkData.FAWorkMode,
1013         FWorkData.FAWorkCountMax,
1014                 FNumber, FDownloadTitle);
1015 end;
1016
1017 procedure TDownloadThread.FireWorkEnd;
1018 begin
1019         OnWorkEnd(FWorkData.FSender, FWorkData.FAWorkMode,
1020                 FNumber);
1021 end;
1022
1023 procedure TDownloadThread.FireWork;
1024 begin
1025         OnWork(FWorkData.FSender, FWorkData.FAWorkMode,
1026         FWorkData.FAWorkCount,
1027                 FNumber);
1028 end;
1029
1030 function TDownloadThread.ParseCgiStatus(Content: string): TCgiStatus;
1031 var
1032         StatusLine: string;
1033         Line: string;
1034         Idx: Integer;
1035         Status: string;
1036         Size: string;
1037         Msg: string;
1038 begin
1039 // [+OK] \82Ì\8fê\8d\87\82Í\8d·\95ª
1040 // [-INCR] (Incorrect)\82Ì\8fê\8d\87\82Í\82·\82×\82Ä\82Ì\83f\81[\83^
1041 // [-ERR (\83e\83L\83X\83g)]\82Ì\8fê\8d\87\82Í\82È\82ñ\82©\83G\83\89\81[
1042 // \97á\81F+OK 23094/512K
1043 //               -INCR 23094/512K
1044 //               -ERR \82»\82ñ\82È\94Â\82È\82¢\82Å\82·
1045         Idx := AnsiPos(#10, Content);
1046         StatusLine := Copy(Content, 0, Idx);
1047
1048         Idx := AnsiPos(' ', Content);
1049         Status := Copy(StatusLine, 0, Idx - 1);
1050         Line := Copy(StatusLine, Idx + 1, Length(StatusLine));
1051
1052 //      Idx := AnsiPos('/', Line);
1053         if Trim(Status) = '-ERR' then
1054                 Msg := Trim(Line)
1055         else
1056                 Size := Copy(Line, 0, Idx - 1);
1057
1058         if Trim(Status) = '+OK' then
1059                 Result.FStatus := gcsOK
1060         else if Trim(Status) = '-INCR' then
1061                 Result.FStatus := gcsINCR
1062         else if Trim(Status) = '-ERR' then begin
1063                 Result.FStatus := gcsERR;
1064                 Result.FErrText := Msg;
1065                 Result.FSize := 0;
1066                 Exit;
1067         end else begin
1068                 {$IFDEF DEBUG}
1069                 Writeln(Status);
1070                 {$ENDIF}
1071                 Result.FStatus := gcsERR;
1072                 Result.FErrText := '\83G\83\89\81[\82È\82ñ\82¾\82¯\82Ç\81A\82æ\82­\95ª\82©\82ç\82È\82¢\83G\83\89\81[';
1073                 Result.FSize := 0;
1074                 Exit;
1075         end;
1076
1077         if GikoSys.IsNumeric(Size) then
1078                 Result.FSize := StrToInt(Size)
1079         else begin
1080                 Result.FSize := 0;
1081                 Result.FStatus := gcsERR;
1082                 Result.FErrText := '\83X\83e\81[\83^\83X\89ð\90Í\8e¸\94s[' + StatusLine + ']';
1083         end;
1084 end;
1085
1086 function TDownloadThread.ParseRokkaStatus(Content: string): TCgiStatus;
1087 var
1088         StatusLine: string;
1089         Idx: Integer;
1090         Status: string;
1091 begin
1092 //      \81@\83\8c\83X\83|\83\93\83X : 1\8ds\96Ú\82Érokka\82Ì\8f\88\97\9d\8c\8b\89Ê\82ª\8bL\8fq\82³\82ê\82Ü\82·
1093 //      \81@\81@"Success XXX"\81@- \90¬\8c÷\81@XXX\82Édat\82Ì\8fó\91Ô\81i\8eæ\93¾\8c³\81j\82ª\8bL\8fq\82³\82ê\82Ü\82·
1094 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@Live\81@\81@\81@\81@\83\89\83C\83u\83X\83\8c\83b\83h
1095 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@Pool\81@\81@\81@\81@dat\97\8e\82¿\83X\83\8c\83b\83h
1096 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@Archive \81@\81@\89ß\8b\8e\83\8d\83O
1097 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81\88È\8d~\82Ì\8ds\82ÉDAT\8c`\8e®(name<>email<>datetime<>body<>[title])\82Å\83\8d\83O\82ª\8bL\8fq\82³\82ê\82Ä\82¢\82Ü\82·
1098 //      \81@\81@"Error XXX"\81@\81@- \89½\82ç\82©\82Ì\83G\83\89\81[\82Å\82·\81@XXX \82ª\83G\83\89\81[\83R\81[\83h\82Å\82·\81B
1099 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@13 \81@\81@\81@not found\81@\81@\81@\81@\81@\81@\97v\8b\81\82³\82ê\82½dat\82ª\8c©\82Â\82©\82è\82Ü\82¹\82ñ\82Å\82µ\82½
1100 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@8008135\81@inputError \81@\81@\81@\81@\81@\83\8a\83N\83G\83X\83gURL\82ÌSERVER\82©BOARD\82ª\90³\82µ\82­\82È\82¢\82Å\82·
1101 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@666\81@\81@\81@urlError \81@\81@\81@\81@\81@\81@OPTIONS\82Ü\82½\82ÍQueryString\82ª\90³\82µ\82­\82È\82¢\82Å\82·
1102 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@69 \81@\81@\81@authenticationError\81@KAGI\82ª\95s\90³\81i\97L\8cø\8aú\8cÀ\90Ø\82ê\82»\82Ì\91¼\81j
1103 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@420\81@\81@\81@timeLimitError \81@\81@\81@\83A\83N\83Z\83X\8aÔ\8au\82ª\92Z\82·\82¬\82Ü\82·
1104 //      \81@\81@\81@\81@\81@\81@\81@\81@\81@\81@\81@42 \81@\81@\81@methodError\81@\81@\81@\81@\81@\82»\82ÌHTTP\83\81\83\\83b\83h\82Í\8b\96\89Â\82³\82ê\82Ä\82¢\82Ü\82¹\82ñ
1105         Idx := AnsiPos(#10, Content);
1106     if (Idx > 0) then
1107             StatusLine := Copy(Content, 0, Idx)
1108     else
1109         StatusLine := Content;
1110
1111     if (AnsiPos('Success', StatusLine) = 1) then begin
1112                 Result.FStatus := gcsOK;
1113         Delete(StatusLine, 1, 7);
1114         Status := Trim(StatusLine);
1115         if (Status = 'Live') then                   // \91½\95ª\82±\82ê\82Í\97\88\82È\82¢
1116                 Result.FErrText := '\8eæ\93¾\90¬\8c÷\81i\83\89\83C\83u\83X\83\8c\83b\83h\81j'
1117         else if (Status = 'Pool') then
1118                 Result.FErrText := '\8eæ\93¾\90¬\8c÷\81idat\97\8e\82¿\83X\83\8c\83b\83h\81j'
1119         else if (Status = 'Archive') then
1120                 Result.FErrText := '\8eæ\93¾\90¬\8c÷\81i\89ß\8b\8e\83\8d\83O\81j'
1121         else    // ???
1122                 Result.FErrText := '\8eæ\93¾\90¬\8c÷';
1123     end
1124     else if (AnsiPos('Error', StatusLine) = 1) then begin
1125                 Result.FStatus := gcsERR;
1126         Delete(StatusLine, 1, 5);
1127         Status := Trim(StatusLine);
1128         if (Status = '13') then
1129                 Result.FErrText := '\97v\8b\81\82³\82ê\82½dat\82ª\8c©\82Â\82©\82è\82Ü\82¹\82ñ\82Å\82µ\82½'
1130         else if (Status = '8008135') then
1131                 Result.FErrText := '\83\8a\83N\83G\83X\83gURL\82ÌSERVER\82©BOARD\82ª\90³\82µ\82­\82È\82¢\82Å\82·'
1132         else if (Status = '666') then
1133                 Result.FErrText := 'OPTIONS\82Ü\82½\82ÍQueryString\82ª\90³\82µ\82­\82È\82¢\82Å\82·'
1134         else if (Status = '69') then
1135                 Result.FErrText := 'KAGI\82ª\95s\90³\81i\97L\8cø\8aú\8cÀ\90Ø\82ê\82»\82Ì\91¼\81j'
1136         else if (Status = '20') then
1137                 Result.FErrText := '\83A\83N\83Z\83X\8aÔ\8au\82ª\92Z\82·\82¬\82Ü\82·'
1138         else if (Status = '42') then
1139                 Result.FErrText := '\82»\82ÌHTTP\83\81\83\\83b\83h\82Í\8b\96\89Â\82³\82ê\82Ä\82¢\82Ü\82¹\82ñ'
1140         else    // ???
1141                 Result.FErrText := '\8eæ\93¾\83G\83\89\81[[' + Status + ']';
1142     end
1143     else begin
1144                 Result.FStatus := gcsERR;
1145                 Result.FErrText := '\83X\83e\81[\83^\83X\89ð\90Í\8e¸\94s[' + StatusLine + ']';
1146     end;
1147         Result.FSize := 0;
1148 end;
1149
1150 //\82P\8ds\96Ú\82ð\8fÁ\82µ\82Ä\81A\83R\83\93\83e\83\93\83c\83T\83C\83Y\82ð\90Ý\92è\82·\82é
1151 procedure TDownloadThread.DeleteStatusLine(Item: TDownloadItem);
1152 var
1153         SList: TStringList;
1154 begin
1155         SList := TStringList.Create;
1156         try
1157                 SList.Text := Item.Content;
1158                 //1\8ds\96Ú\82ð\8dí\8f\9c
1159                 if SList.Count > 1 then
1160                         SList.Delete(0);
1161         Item.Content := SList.Text;
1162                 //\89ü\8ds\83R\81[\83h\82ðCRLF -> LF\82Æ\8dl\82¦\82Ä\81A\8ds\90\94\95ª\82¾\82¯\83}\83C\83i\83X
1163         Item.ContentLength := Length(SList.Text) - SList.Count;
1164         finally
1165                 SList.Free;
1166         end;
1167 end;
1168
1169 procedure TDownloadItem.SaveListFile;
1170 var
1171         i: Integer;
1172         index: Integer;
1173         NewItem: TThreadItem;
1174         NumCount: Integer;
1175         Body: TStringList;
1176         Rec: TSubjectRec;
1177         {$IFDEF DEBUG}
1178         st, rt : Cardinal;
1179         {$ENDIF}
1180         function MakeThreadCallBack(
1181                 inInstance      : DWORD;        // TBoardItem \82Ì\83C\83\93\83X\83^\83\93\83X
1182                 inURL                           : PChar;        // \83X\83\8c\83b\83h\82Ì URL
1183                 inTitle                 : PChar;        // \83X\83\8c\83^\83C
1184                 inCount                 : DWORD         // \83\8c\83X\82Ì\90\94
1185         ) : Boolean; stdcall;           // \97ñ\8b\93\82ð\91±\82¯\82é\82È\82ç True
1186         var
1187                 _ThreadItem     : TThreadItem;  // '_' \82Í\83N\83\89\83X\82Ì\83v\83\8d\83p\83e\83B\82Æ\82©\82Ô\82Á\82Ä\82é\82Ì\82Å
1188                 boardItem               : TBoard;
1189         begin
1190                 Result          := True;
1191                 boardItem       := TBoard( inInstance );
1192
1193                 boardItem.IntData := boardItem.IntData + 1;
1194                 if boardItem.IntData < (boardItem.Count shr      2) then
1195                         index := boardItem.GetIndexFromURL( string( inURL ) )
1196                 else
1197                         index := boardItem.GetIndexFromURL( string( inURL ), True );
1198                 if index = -1 then begin
1199                         //\90V\82µ\82¢\83X\83\8c\83b\83h
1200                         _ThreadItem := TThreadItem.Create( boardItem.BoardPlugIn, boardItem, string( inURL ) );
1201
1202                         _ThreadItem.Title                                       := string( inTitle );
1203                         _ThreadItem.AllResCount         := inCount;
1204                         _ThreadItem.ParentBoard         := Board;
1205                         _ThreadItem.No                                          := boardItem.IntData;
1206                         _ThreadItem.RoundDate           := ZERO_DATE;
1207                         _ThreadItem.LastModified        := ZERO_DATE;
1208                         _ThreadItem.AgeSage                             := gasNew;
1209                         boardItem.Add(_ThreadItem);
1210                 end else begin
1211                         //\8f\87\88Ê\82ª\8fã\82ª\82Á\82Ä\82¢\82ê\82ÎAge\82É\82·\82é
1212                         if boardItem.Items[index].No > boardItem.IntData then
1213                                 boardItem.Items[index].AgeSage := gasAge
1214                         //\8f\87\88Ê\82ª\8fã\82ª\82Á\82Ä\82È\82¢\82¯\82Ç\81A\83\8c\83X\82ª\82Â\82¢\82Ä\82½\82ç\81ASage\82É
1215                         else if boardItem.Items[index].AllResCount <> inCount then
1216                                 boardItem.Items[index].AgeSage := gasSage
1217                         //\8f\87\88Ê\8fã\82ª\82Á\82Ä\82È\82¢\82µ\81A\83\8c\83X\82Ì\91\9d\8c¸\82à\96³\82¯\82ê\82Î\81ANone
1218                         else
1219                                 boardItem.Items[index].AgeSage := gasNone;
1220
1221                         boardItem.Items[index].No                                               := boardItem.IntData;
1222                         boardItem.Items[index].AllResCount      := inCount;
1223                 end;
1224
1225         end;
1226 begin
1227 {$IFDEF DEBUG}
1228         st := GetTickCount;
1229         Writeln('SAVELIST');
1230 {$ENDIF}
1231         //Board.ListData := TList.Create;
1232         Body := TStringList.Create;
1233         try
1234                 //\83_\83E\83\93\83\8d\81[\83h\93ú\8e\9e\90Ý\92è\81i\83\8d\81[\83J\83\8b\93ú\8e\9e\81j
1235                 Board.RoundDate := Now;
1236                 //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
1237                 Board.LastModified := LastModified;
1238
1239
1240                 //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é
1241                 if GikoSys.Setting.DatOchiSortIndex >= 0 then begin
1242                         Sort.SetSortNoFlag(true);
1243                         Sort.SetSortOrder(GikoSys.Setting.DatOchiSortOrder);
1244                         Sort.SetSortIndex(GikoSys.Setting.DatOchiSortIndex);
1245                         //Sort.SortNonAcquiredCountFlag := GikoSys.Setting.NonAcquiredCount;
1246                         Board.CustomSort(ThreadItemSortProc);
1247                 end;
1248
1249 {$IFDEF DEBUG}
1250         rt := GetTickCount - st;
1251         Writeln('END Sortd' + IntToStr(rt) + ' ms');
1252 {$ENDIF}
1253
1254                 for i := Board.Count - 1 downto 0 do
1255                         Board.Items[i].AgeSage := gasNull;
1256
1257                 if Board.IsBoardPlugInAvailable then begin
1258                         // \90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
1259                         // \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Á
1260                         // \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¬
1261                         Board.IntData := 0;
1262 {$IFDEF DEBUG}
1263         rt := GetTickCount - st;
1264         Writeln('Start Enum' + IntToStr(rt) + ' ms');
1265 {$ENDIF}
1266
1267                         //\82±\82ê\82ª\92x\82¢\81@\97v\89ü\91P
1268                         Board.BeginUpdate;
1269                         Board.BoardPlugIn.EnumThread( DWORD( Board ), @MakeThreadCallBack );
1270                         Board.EndUpdate;
1271
1272 {$IFDEF DEBUG}
1273         rt := GetTickCount - st;
1274         Writeln('End Enum' + IntToStr(rt) + ' ms');
1275 {$ENDIF}
1276
1277                         //\8cÃ\82¢\83\8a\83X\83g\82É\82µ\82©\82È\82¢\82â\82Â\82ç\82ð\8dí\8f\9c
1278                         for i := Board.Count - 1 downto 0 do begin
1279                                 if( Board.Items[i].AgeSage = gasNull )and not (Board.Items[i].IsLogFile) then
1280                                         Board.Delete(i);
1281                         end;
1282
1283                         // \90V\82µ\82¢\83\8a\83X\83g\82É\96³\82©\82Á\82½\83A\83C\83e\83\80\82ð\90V\82µ\82¢\83\8a\83X\83g\82É\92Ç\89Á
1284                         for i := 0 to Board.Count - 1 do begin
1285                                 if(Board.Items[i].AgeSage = gasNull) and (Board.Items[i].IsLogFile) then begin
1286                                         Board.IntData := Board.IntData + 1;
1287                                         Board.Items[i].No                                               := Board.IntData;
1288                                         Board.Items[i].AllResCount      := Board.Items[i].Count;
1289                                         Board.Items[i].NewResCount      := 0;
1290                                         Board.Items[i].AgeSage                  := gasArch;
1291                                 end;
1292                         end;
1293
1294                 end else begin
1295                         //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
1296                         //\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Á
1297                         //\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¬
1298                         Body.Text := Content;
1299                         NumCount := 0;
1300                         for i := 0 to Body.Count - 1 do begin
1301                                 Rec := GikoSys.DivideSubject(Body[i]);
1302                                 Rec.FFileName := Trim(Rec.FFileName);
1303                                 if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
1304                                 Inc(NumCount);
1305                                 index := Board.GetIndexFromFileName(Rec.FFileName);
1306                                 if index = -1 then begin
1307                                         //\90V\82µ\82¢\83X\83\8c\83b\83h
1308                                         NewItem := TThreadItem.Create(
1309                                                                 nil,
1310                                 Board,
1311                                 GikoSys.Get2chBoard2ThreadURL( Board, ChangeFileExt( Rec.FFileName, '' ) ) );
1312                                         NewItem.Title := Rec.FTitle;
1313                                         NewItem.AllResCount := Rec.FCount;
1314                                         NewItem.ParentBoard := Board;
1315                                         NewItem.No := NumCount;
1316                                         NewItem.RoundDate := ZERO_DATE;
1317                                         NewItem.LastModified := ZERO_DATE;
1318                                         NewItem.AgeSage := gasNew;
1319                                         Board.Add(NewItem);
1320                                 end else begin
1321                                         if Board.Items[index].No > NumCount then
1322                                                 Board.Items[index].AgeSage := gasAge
1323                                         else if Board.Items[index].AllResCount < Rec.FCount then
1324                                                 Board.Items[index].AgeSage := gasSage
1325                                         else
1326                                                 Board.Items[index].AgeSage := gasNone;
1327
1328                                         Board.Items[index].No := NumCount;
1329                                         Board.Items[index].AllResCount := Rec.FCount;
1330                                 end;
1331                         end;
1332                         //\8cÃ\82¢\83\8a\83X\83g\82Ì\8dí\8f\9c
1333                         for i := Board.Count - 1 downto 0 do begin
1334                                 if( Board.Items[i].AgeSage = gasNull )and not (Board.Items[i].IsLogFile) then
1335                                         Board.Delete(i);
1336                         end;
1337
1338                         //\90V\82µ\82¢\83\8a\83X\83g\82É\96³\82©\82Á\82½\83A\83C\83e\83\80\82Ì\8dX\90V
1339                         for i := 0 to Board.Count - 1 do begin
1340                                 if( Board.Items[i].AgeSage = gasNull )and (Board.Items[i].IsLogFile) then begin
1341                                         inc(NumCount);
1342                                         Board.Items[i].No := NumCount;
1343                                         Board.Items[i].AllResCount := Board.Items[i].Count;
1344                                         Board.Items[i].NewResCount := 0;
1345                                         Board.Items[i].AgeSage := gasArch;
1346                                 end;
1347                         end;
1348                         //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
1349                         GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
1350             Body.Text := MojuUtils.Sanitize(Body.Text);
1351                         Body.SaveToFile(Board.GetSubjectFileName);
1352                 end;
1353         finally
1354                 Body.Free;
1355         end;
1356
1357
1358 end;
1359
1360 {procedure TDownloadItem.SaveListFile;
1361 var
1362         i: Integer;
1363         index: Integer;
1364         NewItem: TThreadItem;
1365         NewList: TList;
1366 //      SaveCount: Integer;
1367         NumCount: Integer;
1368         Body: TStringList;
1369         Rec: TSubjectRec;
1370 begin
1371         NewList := TList.Create;
1372         Body := TStringList.Create;
1373         try
1374                 //\8f\84\89ñ\93ú\8e\9e\90Ý\92è
1375                 Board.RoundDate := Now;
1376                 //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
1377                 Board.LastModified := LastModified;
1378
1379                 //\83\8a\83X\83g\95Û\91\8c\8f\90\94\8eæ\93¾
1380                 //SaveCount := MaxInt;
1381
1382                 //\8cÃ\82¢\83\8a\83X\83g\82©\82ç\83\8d\83O\96³\82µ\83A\83C\83e\83\80\82ð\8dí\8f\9c
1383                 for i := Board.Count - 1 downto 0 do
1384                         if not Board.Items[i].IsLogFile then
1385                                 Board.Delete(i);
1386
1387                 //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
1388                 //\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Á
1389                 //\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¬
1390                 Body.Text := Content;
1391 //              Loop := Min(Body.Count, SaveCount);
1392                 NumCount := 0;
1393 //              for i := 0 to Loop - 1 do begin
1394                 for i := 0 to Body.Count - 1 do begin
1395                         if i = 0 then Continue; //\82P\8ds\96Ú\82Í\83X\83e\81[\83^\83X\8ds\82Ì\82½\82ß\8f\88\97\9d\82È\82µ
1396
1397                         Rec := GikoSys.DivideSubject(Body[i]);
1398                         if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
1399                         Inc(NumCount);
1400                         index := Board.GetIndex(Rec.FFileName);
1401                         if index = -1 then begin
1402                                 NewItem := TThreadItem.Create;
1403                                 NewItem.FileName := Rec.FFileName;
1404                                 NewItem.Title := Rec.FTitle;
1405                                 NewItem.Count := Rec.FCount;
1406                                 NewItem.ParentBoard := Board;
1407                                 NewItem.No := NumCount;
1408                                 NewItem.RoundDate := ZERO_DATE;
1409                                 NewItem.LastModified := ZERO_DATE;
1410                                 NewList.Add(NewItem);
1411                         end else begin
1412                                 //Board.Items[index].Count := Count;
1413                                 Board.Items[index].No := NumCount;
1414                                 NewList.Add(Board.Items[index]);
1415                                 Board.DeleteList(index);
1416                         end;
1417                 end;
1418
1419                 //\90V\82µ\82¢\83\8a\83X\83g\82É\96³\82©\82Á\82½\8cÃ\82¢\83\8d\83O\97L\82è\83A\83C\83e\83\80\82ð\90V\82µ\82¢\83\8a\83X\83g\82É\92Ç\89Á
1420                 for i := 0 to Board.Count - 1 do begin
1421                         inc(NumCount);
1422                         Board.Items[i].No := NumCount;
1423                         NewList.Add(Board.Items[i]);
1424                 end;
1425
1426                 //\8cÃ\82¢\83\8a\83X\83g\82ð\8fÁ\82·\81i\83\8a\83X\83g\82Ì\82Ý\81B\83X\83\8c\83I\83u\83W\83F\83N\83g\8e©\91Ì\82Í\8fÁ\82³\82È\82¢\81j
1427                 for i := Board.Count - 1 downto 0 do
1428                         Board.DeleteList(i);
1429
1430                 //\90V\82µ\82¢\83\8a\83X\83g\82ð\83{\81[\83h\83I\83u\83W\83F\83N\83g\82É\92Ç\89Á
1431                 for i := 0 to NewList.Count - 1 do
1432                         Board.Add(TThreadItem(NewList[i]));
1433
1434                 //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
1435 //              GikoSys.ForceDirectoriesEx(GikoSys.GetLogDir + Board.BBSID);
1436 //              Body.SaveToFile(GikoSys.GetSubjectFileName(Board.BBSID));
1437                 GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
1438                 Body.SaveToFile(Board.GetSubjectFileName);
1439         finally
1440                 Body.Free;
1441                 NewList.Free;
1442         end;
1443 end;
1444 }
1445 procedure TDownloadItem.SaveItemFile;
1446 var
1447         Body, oldBody: TStringList;
1448         Cnt: Integer;
1449         OldCnt: Integer;
1450         FileName: string;
1451         ini: TMemIniFile;
1452         Res: TResRec;
1453         NewRes: Integer;
1454         finish : Boolean;
1455         loopCnt : Integer;
1456         LastIdx : Integer;
1457 begin
1458         FileName := ThreadItem.GetThreadFileName;
1459
1460         //if not ThreadItem.IsBoardPlugInAvailable then begin
1461     if not ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1462                 if Trim(Content) = '' then
1463                         Exit;
1464
1465                 GikoSys.ForceDirectoriesEx(ExtractFilePath(FileName));
1466
1467                 //      Cnt := 0;
1468                 Body := TStringList.Create;
1469                 NewRes := 0;
1470                 OldCnt := 0;
1471                 try
1472                 //              if FileExists(FileName) and (ResponseCode = 206) then begin
1473                         if FileExists(FileName) and (State = gdsDiffComplete) then begin
1474                                 loopCnt := 10;
1475                                 repeat
1476                                         finish := true;
1477                                         try
1478                                                 Body.LoadFromFile(FileName);
1479                                                 OldCnt := Body.Count;
1480                                                 Body.Text := Body.Text + Content;
1481                                                 Body.SaveToFile(FileName);
1482                                                 NewRes := Body.Count - OldCnt;
1483                                         except
1484                                                 on E:EFOpenError do begin
1485                                                         sleep(10);
1486                                                         Dec(loopCnt);
1487                                                         if loopCnt > 0 then
1488                                                                 finish := false;
1489                                                 end;
1490                                         end;
1491                                 until finish;
1492                                 //Cnt := Body.Count;
1493                         end else begin
1494                                 if IsAbone then begin
1495                                         // \82 \82Ú\81[\82ñ\82ð\8c\9f\8fo\82µ\82½\82Ì\82Å\82±\82±\82Ü\82Å\93Ç\82ñ\82¾\82Æ\90V\92\85\83\8c\83X\94Ô\82Ì\82Â\82¯\82È\82¨\82µ
1496                                         oldBody := TStringList.Create;
1497                                         try
1498                                                 loopCnt := 10;
1499                                                 repeat
1500                                                         finish := true;
1501                                                         try
1502                                                                 oldBody.LoadFromFile(FileName);
1503                                                         except
1504                                                                 on E:EFOpenError do begin
1505                                                                         sleep(10);
1506                                                                         Dec(loopCnt);
1507                                                                         if loopCnt > 0 then
1508                                                                                 finish := false
1509                                                                         else
1510                                                                                 finish := true;
1511                                                                 end;
1512                                                         end;
1513                                                 until finish;
1514
1515                                                 Body.Text := Content;
1516                                                 if (ThreadItem.Kokomade > 0) and (ThreadItem.Kokomade <= oldBody.Count) then begin
1517                                                         ThreadItem.Kokomade := Body.IndexOf(oldBody.Strings[ ThreadItem.Kokomade - 1 ]);
1518                                                         if ThreadItem.Kokomade <> -1 then ThreadItem.Kokomade := ThreadItem.Kokomade + 1;
1519                                                 end;
1520
1521                                                 LastIdx := oldBody.Count;
1522                                                 repeat
1523                                                         Dec(LastIdx);
1524                                                         OldCnt := Body.IndexOf(oldBody.Strings[ LastIdx ]) + 1;
1525                                                 until ( OldCnt <> 0 ) or (LastIdx = 0);
1526
1527                                                 if OldCnt >= Body.Count then OldCnt := Body.Count - 1;
1528                                                 NewRes := Body.Count - OldCnt;
1529
1530                                                 // \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)
1531                                                 if ThreadItem.Kokomade > OldCnt then begin
1532                                                         if OldCnt > 0 then
1533                                                                 ThreadItem.Kokomade := OldCnt
1534                                                         else
1535                                                                 ThreadItem.Kokomade := 1;
1536                                                 end;
1537
1538                                         finally
1539                                                 oldBody.Free;
1540                                         end;
1541
1542                                 end else begin
1543                                         Body.Text := Content;
1544                                         //ThreadItem.Count := 0;
1545                                         OldCnt := 0;
1546                                         NewRes := Body.Count;
1547                                         //Cnt := Body.Count;
1548                                 end;
1549         //                      if Body.Count > 0 then
1550         //                              Body.Delete(0);
1551                                 Body.SaveToFile(FileName);
1552
1553                                 if ThreadItem.Title = '' then begin
1554                                         THTMLCreate.DivideStrLine(Body[0], @Res);
1555                                         ThreadItem.Title := Res.FTitle;
1556                                 end;
1557                                 ThreadItem.Size := 0;
1558                         end;
1559                         Cnt := Body.Count;
1560                 finally
1561                         Body.Free;
1562                 end;
1563
1564                 ThreadItem.Size := ThreadItem.Size + ContentLength;
1565                 ThreadItem.LastModified := LastModified;
1566                 ThreadItem.Count := Cnt;
1567                 //ThreadItem.AllResCount := Cnt;
1568                 ThreadItem.NewResCount := NewRes;
1569                 ThreadItem.NewReceive := OldCnt + 1;
1570         end;
1571         ThreadItem.AllResCount := ThreadItem.Count;
1572         ThreadItem.IsLogFile := True;
1573         ThreadItem.RoundDate := Now;
1574         if not ThreadItem.UnRead then begin
1575                 ThreadItem.UnRead := True;
1576         end;
1577 //      if ThreadItem.RoundNo = 6 then
1578 //              ThreadItem.RoundNo := 0;
1579
1580         //\88Ù\8fí\8fI\97¹\8e\9e\82Í\83C\83\93\83f\83b\83N\83X\82ª\8dX\90V\82³\82ê\82È\82¢\82½\82ß\81A\83e\83\93\83|\83\89\83\8a\82ð\8dì\90¬\82·\82é\81B
1581         //\90³\8fí\8fI\97¹\8e\9e\82É\82Í\8dí\8f\9c
1582         //\88Ù\8fí\8fI\97¹\8e\9e\82Í\81A\8e\9f\89ñ\8bN\93®\8e\9e\82É\83e\83\93\83|\83\89\83\8a\82ð\8c©\82Ä\8dX\90V
1583         ini := TMemIniFile.Create(ChangeFileExt(FileName, '.tmp'));
1584         try
1585                 ini.WriteDateTime('Setting', 'RoundDate', ThreadItem.RoundDate);
1586                 ini.WriteDateTime('Setting', 'LastModified', ThreadItem.LastModified);
1587                 ini.WriteInteger('Setting', 'Size', ThreadItem.Size);
1588                 ini.WriteInteger('Setting', 'Count', ThreadItem.Count);
1589                 ini.WriteInteger('Setting', 'AllResCount', ThreadItem.AllResCount);
1590                 ini.WriteInteger('Setting', 'NewResCount', ThreadItem.NewResCount);
1591                 ini.WriteInteger('Setting', 'NewReceive', ThreadItem.NewReceive);
1592 //              ini.WriteInteger('Setting', 'RoundNo', ThreadItem.RoundNo);
1593 //              ini.WriteBool('Setting', 'Round', ThreadItem.Round);
1594                 ini.WriteBool('Setting', 'UnRead', ThreadItem.UnRead);
1595                 ini.UpdateFile;
1596         finally
1597                 ini.Free;
1598         end;
1599 end;
1600
1601 end.