OSDN Git Service

5708583de14e0a39e753836331b41a4c2f60ad68
[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, MonaUtils, ExternalBoardManager;
9
10 type
11         TDownloadItem = class;
12         TGikoDownloadType = (gdtBoard, gdtThread);
13         TGikoDownloadState = (gdsWait, gdsWork, gdsComplete, gdsDiffComplete, gdsNotModify, gdsAbort, gdsError);
14         TGikoCgiStatus = (gcsOK, gcsINCR, gcsERR);
15         TGikoDLProgress = (gdpStd, gdpAll, gdpDatOchi, gdpOfflaw);
16
17         TGikoWorkEvent = procedure(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer; ID: Integer) of object;
18         TGikoWorkBeginEvent = procedure(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer; ID: Integer; const AWorkTitle: string) of object;
19         TGikoWorkEndEvent = procedure(Sender: TObject; AWorkMode: TWorkMode; ID: Integer) of object;
20         TDownloadEndEvent = procedure(Sender: TObject; Item: TDownloadItem) of object;
21         TDownloadMsgEvent = procedure(Sender: TObject; Item: TDownloadItem; Msg: string; Icon: TGikoMessageIcon) of object;
22
23         TCgiStatus = record
24                 FStatus: TGikoCgiStatus;
25                 FSize: Integer;
26                 FErrText: string;
27         end;
28
29
30         TDownloadThread = class(TThread)
31         private
32                 FIndy: TIdHttp;
33                 FItem: TDownloadItem;
34                 FNumber: Integer;
35                 FAbort: Boolean;
36                 FMsg: string;
37                 FIcon: TGikoMessageIcon;
38                 FSessionID: string;
39                 FOnWork: TGikoWorkEvent;
40                 FOnWorkBegin: TGikoWorkBeginEvent;
41                 FOnWorkEnd: TGikoWorkEndEvent;
42                 FOnDownloadEnd: TDownloadEndEvent;
43                 FOnDownloadMsg: TDownloadMsgEvent;
44                 FDownloadTitle: string;
45
46                 procedure FireDownloadEnd;
47                 procedure FireDownloadMsg;
48                 procedure GetSessionID;
49                 procedure WorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
50                 procedure WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
51                 procedure Work(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
52                 function ParseCgiStatus(Content: string): TCgiStatus;
53                 function CgiDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime): Boolean;
54                 function DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
55                 function DeleteStatusLine(Content: string): string;
56         protected
57                 procedure Execute; override;
58         public
59                 property Item: TDownloadItem read FItem write FItem;
60                 property Number: Integer read FNumber write FNumber;
61                 constructor Create(CreateSuspended: Boolean);
62         destructor Destroy; override;
63                 procedure Abort;
64                 property OnWork: TGikoWorkEvent read FOnWork write FOnWork;
65                 property OnWorkBegin: TGikoWorkBeginEvent read FOnWorkBegin write FOnWorkBegin;
66                 property OnWorkEnd: TGikoWorkEndEvent read FOnWorkEnd write FOnWorkEnd;
67                 property OnDownloadEnd: TDownloadEndEvent read FOnDownloadEnd write FOnDownloadEnd;
68                 property OnDownloadMsg: TDownloadMsgEvent read FOnDownloadMsg write FOnDownloadMsg;
69         end;
70
71         TDownloadItem = class(TObject)
72         private
73                 FDownType: TGikoDownloadType;
74                 FBoard: TBoard;
75                 FThreadItem: TThreadItem;
76
77                 FContentLength: Integer;
78                 FLastModified: TDateTime;
79                 FContent: string;
80                 FResponseCode: Smallint;
81                 FState: TGikoDownloadState;
82                 FErrText: string;
83                 FForceDownload: Boolean;
84         public
85                 procedure SaveListFile;
86                 procedure SaveItemFile;
87
88                 property DownType: TGikoDownloadType read FDownType write FDownType;
89                 property Board: TBoard read FBoard write FBoard;
90                 property ThreadItem: TThreadItem read FThreadItem write FThreadItem;
91
92                 property ContentLength: Integer read FContentLength write FContentLength;
93                 property LastModified: TDateTime read FLastModified write FLastModified;
94                 property Content: string read FContent write FContent;
95                 property ResponseCode: Smallint read FResponseCode write FResponseCode;
96                 property State: TGikoDownloadState read FState write FState;
97                 property ErrText: string read FErrText write FErrText;
98                 property ForceDownload: Boolean read FForceDownload write FForceDownload;
99         end;
100
101 implementation
102
103 constructor TDownloadThread.Create(CreateSuspended: Boolean);
104 begin
105         inherited Create(CreateSuspended);
106         FIndy := TIdHttp.Create(nil);
107
108         FIndy.OnWorkBegin := WorkBegin;
109         FIndy.OnWorkEnd := WorkEnd;
110         FIndy.OnWork := Work;
111 end;
112
113 destructor TDownloadThread.Destroy;
114 begin
115     FIndy.Request.CustomHeaders.Clear;
116     FIndy.Request.RawHeaders.Clear;
117     FIndy.Request.Clear;
118     FIndy.Response.CustomHeaders.Clear;
119     FIndy.Response.RawHeaders.Clear;
120     FIndy.Response.Clear;
121     FIndy.ProxyParams.Clear;
122         FIndy.Free;
123         inherited;
124 end;
125
126 function RFC1123_Date(aDate : TDateTime) : String;
127 const
128          StrWeekDay : String = 'MonTueWedThuFriSatSun';
129          StrMonth        : String = 'JanFebMarAprMayJunJulAugSepOctNovDec';
130 var
131          Year, Month, Day                        : Word;
132          Hour, Min,      Sec, MSec : Word;
133          DayOfWeek                                                      : Word;
134 begin
135          DecodeDate(aDate, Year, Month, Day);
136          DecodeTime(aDate, Hour, Min,    Sec, MSec);
137          DayOfWeek := ((Trunc(aDate) - 2) mod 7);
138          Result := Copy(StrWeekDay, 1 + DayOfWeek * 3, 3) + ', ' +
139                                                  Format('%2.2d %s %4.4d %2.2d:%2.2d:%2.2d',
140                                                                                 [Day, Copy(StrMonth, 1 + 3 * (Month - 1), 3),
141                                                                                  Year, Hour, Min, Sec]);
142 end;
143
144 procedure TDownloadThread.Execute;
145 var
146         ResStream: TMemoryStream;
147
148         URL: string;
149         CgiStatus: TCgiStatus;
150         Modified: TDateTime;
151         RangeStart: Integer;
152         AdjustLen: Integer;
153         Idx: Integer;
154         ATitle: string;
155         DownloadResult: Boolean;
156         Abone: Boolean;
157         foundPos: Integer;
158         boardPlugIn : TBoardPlugIn;
159         listContent : string;
160 begin
161         while not Terminated do begin
162                 //===== \83v\83\89\83O\83C\83\93
163                 boardPlugIn := nil;
164                 ExternalBoardManager.OnWork                             := Work;
165                 ExternalBoardManager.OnWorkBegin        := WorkBegin;
166                 ExternalBoardManager.OnWorkEnd          := WorkEnd;
167
168                 FDownloadTitle := '';
169                 case FItem.FDownType of
170                 gdtBoard:
171                         begin
172                                 FDownloadTitle := FItem.FBoard.Title;
173                                 if FItem.FBoard <> nil then begin
174                                         if FItem.FBoard.IsBoardPlugInAvailable then begin
175                                                 boardPlugIn     := FItem.FBoard.BoardPlugIn;
176                                                 Item.State      := TGikoDownloadState( boardPlugIn.DownloadBoard( DWORD( FItem.FBoard ) ) );
177                                         end;
178                                 end;
179                         end;
180                 gdtThread:
181                         begin
182                                 FDownloadTitle := FItem.FThreadItem.Title;
183                                 if FItem.FThreadItem <> nil then begin
184                                         if FItem.FThreadItem.IsBoardPlugInAvailable then begin
185                                                 boardPlugIn     := FItem.FThreadItem.BoardPlugIn;
186                                                 Item.State      := TGikoDownloadState( boardPlugIn.DownloadThread( DWORD( FItem.FThreadItem ) ) );
187                                         end;
188                                 end;
189                         end;
190                 end;
191                 if Length(FDownloadTitle) = 0 then
192                         FDownloadTitle := '\81i\96¼\8fÌ\95s\96¾\81j';
193
194                 if boardPlugIn <> nil then begin
195                         if FAbort then
196                                 Item.State := gdsAbort;
197                         if Assigned( OnDownloadEnd ) then
198                                 Synchronize( FireDownloadEnd );
199                         if Terminated then
200                                 Break;
201
202                         Suspend;
203                         Continue;
204                 end;
205
206                 //===== \83v\83\89\83O\83C\83\93\82ð\8eg\97p\82µ\82È\82¢\8fê\8d\87
207                 FAbort := False;
208                 FIndy.Request.CustomHeaders.Clear;
209                 FIndy.Response.Clear;
210                 FIndy.Request.Clear;
211     FIndy.ProxyParams.Clear;
212     FIndy.Disconnect;
213                 FIndy.Request.UserAgent := GikoSys.GetUserAgent;
214                 FIndy.RecvBufferSize := Gikosys.Setting.RecvBufferSize;
215                 FIndy.ProxyParams.BasicAuthentication := False;
216                 {$IFDEF DEBUG}
217                 Writeln('------------------------------------------------------------');
218                 {$ENDIF}
219                 //FIndy.AllowCookies := False;
220                 if GikoSys.Setting.ReadProxy then begin
221                         if GikoSys.Setting.ProxyProtocol then
222                                 FIndy.ProtocolVersion := pv1_1
223                         else
224                                 FIndy.ProtocolVersion := pv1_0;
225                         FIndy.ProxyParams.ProxyServer := GikoSys.Setting.ReadProxyAddress;
226                         FIndy.ProxyParams.ProxyPort := GikoSys.Setting.ReadProxyPort;
227                         FIndy.ProxyParams.ProxyUsername := GikoSys.Setting.ReadProxyUserID;
228                         FIndy.ProxyParams.ProxyPassword := GikoSys.Setting.ReadProxyPassword;
229                         if GikoSys.Setting.ReadProxyUserID <> '' then
230                                 FIndy.ProxyParams.BasicAuthentication := True;
231                         {$IFDEF DEBUG}
232                         Writeln('\83v\83\8d\83L\83V\90Ý\92è\82 \82è');
233                         Writeln('\83z\83X\83g: ' + GikoSys.Setting.ReadProxyAddress);
234                         Writeln('\83|\81[\83g: ' + IntToStr(GikoSys.Setting.ReadProxyPort));
235                         {$ENDIF}
236                 end else begin
237                         if GikoSys.Setting.Protocol then
238                                 FIndy.ProtocolVersion := pv1_1
239                         else
240                                 FIndy.ProtocolVersion := pv1_0;
241                         FIndy.ProxyParams.ProxyServer := '';
242                         FIndy.ProxyParams.ProxyPort := 80;
243                         FIndy.ProxyParams.ProxyUsername := '';
244                         FIndy.ProxyParams.ProxyPassword := '';
245                         {$IFDEF DEBUG}
246                         Writeln('\83v\83\8d\83L\83V\90Ý\92è\82È\82µ');
247                         {$ENDIF}
248                 end;
249
250                 FIndy.Request.ContentRangeStart := 0;
251                 FIndy.Request.LastModified := ZERO_DATE;
252                 ResStream := TMemoryStream.Create;
253                 try
254                         try
255                                 //********************
256                                 //DAT or Subject\8eæ\93¾
257                                 //********************
258                                 Item.ResponseCode := 0;
259                                 RangeStart := 0;
260                                 AdjustLen := 0;
261                                 Modified := 0;
262                                 if Item.DownType = gdtBoard then begin
263                                         {$IFDEF DEBUG}
264                                         Writeln('Subject\8eæ\93¾');
265                                         Writeln('URL: ' + Item.Board.GetReadCgiURL);
266                                         Writeln('Modified: ' + FloatToStr(Item.Board.LastModified));
267                                         {$ENDIF}
268                                         URL := Item.Board.GetReadCgiURL;
269                                         if Item.ForceDownload then begin
270                                                 // \8b­\90§\8eæ\93¾
271                                                 ATitle := Item.Board.Title;
272                                                 if ATitle = '' then
273                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
274                                                 FMsg := '\81\9a\8b­\90§\8eæ\93¾\82ð\8ds\82¢\82Ü\82· - [' + ATitle + ']';
275                                                 FIcon := gmiWhat;
276                                                 if Assigned(OnDownloadMsg) then
277                                                         Synchronize(FireDownloadMsg);
278                                                 Modified := ZERO_DATE
279                                         end else begin
280                                                 Modified := Item.Board.LastModified;
281                                         end;
282                                 end else if Item.DownType = gdtThread then begin
283                                         {$IFDEF DEBUG}
284                                         Writeln('DAT\8eæ\93¾');
285                                         Writeln('URL: ' + Item.ThreadItem.GetDatURL);
286                                         Writeln('Modified: ' + FloatToStr(Item.ThreadItem.LastModified));
287                                         {$ENDIF}
288                                         URL := Item.ThreadItem.GetDatURL;
289                                         if Item.ForceDownload then begin
290                                                 // \8b­\90§\8eæ\93¾
291                                                 ATitle := Item.ThreadItem.Title;
292                                                 if ATitle = '' then
293                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
294                                                 FMsg := '\81\9a\8b­\90§\8eæ\93¾\82ð\8ds\82¢\82Ü\82· - [' + ATitle + ']';
295                                                 FIcon := gmiWhat;
296                                                 if FileExists(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG')) = true then
297                                                         DeleteFile(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG'));
298                                                 if Assigned(OnDownloadMsg) then
299                                                         Synchronize(FireDownloadMsg);
300                                                 Modified := ZERO_DATE;
301                                                 RangeStart := 0;
302                                                 AdjustLen := 0;
303                                         end else begin
304                                                 Modified := Item.ThreadItem.LastModified;
305                                                 if Item.ThreadItem.Size > 0 then begin
306                                                         {$IFDEF DEBUG}
307                                                         Writeln('RangeStart: ' + IntToStr(Item.ThreadItem.Size));
308                                                         {$ENDIF}
309                                                         //\82 \82Ú\81[\82ñ\83`\83F\83b\83N\82Ì\82½\82ß\82P\83o\83C\83g\91O\82©\82ç\8eæ\93¾
310                                                         RangeStart := Item.ThreadItem.Size;
311                                                         AdjustLen := -1;
312                                                 end;
313                                         end;
314                                 end;
315                                 Abone := False;
316                                 DownloadResult := DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen);
317                                 {$IFDEF DEBUG}
318                                 Writeln('ResponseCode: ' + IntToStr(FIndy.ResponseCode));
319                                 {$ENDIF}
320                                 if Item.DownType = gdtThread then begin
321                                         if Item.ResponseCode = 416 then begin
322                                                 Abone := True;
323                                                 DownloadResult := True;
324                                         end else if DownloadResult and (AdjustLen = -1) and (Item.Content[1] <> #10) then
325                                                 Abone := True;
326                                 end;
327
328                                 if Trim(FIndy.Response.RawHeaders.Values['Date']) <> '' then begin
329                                         if Item.DownType = gdtBoard then
330                                                 Item.Board.LastGetTime := MonaUtils.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date'])
331                                         else
332                                                 Item.ThreadItem.ParentBoard.LastGetTime := MonaUtils.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date']);
333                                 end;
334
335                                 if DownloadResult then begin
336                                         {$IFDEF DEBUG}
337                                         Writeln('Date:' + FIndy.Response.RawHeaders.Values['Date']);
338                                         {$ENDIF}
339                                         if Abone then begin
340                                                 {$IFDEF DEBUG}
341                                                 Writeln('\82 \82Ú\81[\82ñ\8c\9f\8fo');
342                                                 {$ENDIF}
343                                                 ATitle := Item.ThreadItem.Title;
344                                                 if ATitle = '' then
345                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
346                                                 //\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¾
347                                                 RangeStart := 0;
348                                                 AdjustLen := 0;
349                                                 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 + ']';
350                                                 FIcon := gmiWhat;
351                                                 if FileExists(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG')) = true then
352                                                         DeleteFile(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG'));
353                                                 if Assigned(OnDownloadMsg) then
354                                                         Synchronize(FireDownloadMsg);
355                                                 if not DatDownload(Item.DownType, URL, ZERO_DATE, RangeStart, AdjustLen) then
356                                                         Item.State := gdsError;
357                                                 {$IFDEF DEBUG}
358                                                 Writeln('\82 \82Ú\81[\82ñ\8dÄ\8eæ\93¾\8cã');
359                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
360                                                 {$ENDIF}
361                                         end else if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] = #10) then begin
362                                                 //\8d·\95ª\8eæ\93¾\82©\82Â\82P\83o\83C\83g\96Ú\82ªLF\82Ì\8fê\8d\87\81i\90³\8fí\8eæ\93¾\81j\82Í\93ª\82ÌLF\82ð\8dí\8f\9c
363                                                 Item.Content := Copy(Item.Content, 2, Length(Item.Content));
364                                         end;
365                                 end else begin
366                                         Item.State := gdsError;
367                                         if (Item.DownType = gdtBoard) and (Item.ResponseCode = 302) then begin
368                                                 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';
369                                                 FIcon := gmiNG;
370                                                 if Assigned(OnDownloadMsg) then
371                                                         Synchronize(FireDownloadMsg);
372                                         end;
373                                 end;
374
375                                 //********************
376                                 //dat.gz\8eæ\93¾(1)
377                                 //********************
378                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
379                                         {$IFDEF DEBUG}
380                                         Writeln('dat.gz\8eæ\93¾');
381                                         {$ENDIF}
382                                         ATitle := Item.ThreadItem.Title;
383                                         if ATitle = '' then
384                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
385                                         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 + ']';
386                                         FIcon := gmiWhat;
387                                         if Assigned(OnDownloadMsg) then
388                                                 Synchronize(FireDownloadMsg);
389                                         URL := Item.ThreadItem.GetDatgzURL;
390                                         Modified := Item.ThreadItem.LastModified;
391                                         RangeStart := 0;
392                                         AdjustLen := 0;
393                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
394                                                 Item.State := gdsError;
395                                         {$IFDEF DEBUG}
396                                         Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
397                                         {$ENDIF}
398                                 end;
399
400                                 //********************
401                                 //dat.gz\8eæ\93¾(2)
402                                 //********************
403 {
404                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
405                                         ATitle := Item.ThreadItem.Title;
406                                         if ATitle = '' then
407                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
408                                         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 + ']';
409                                         FIcon := gmiWhat;
410                                         if Assigned(OnDownloadMsg) then
411                                                 Synchronize(FireDownloadMsg);
412                                         URL := Item.ThreadItem.GetOldDatgzURL;
413                                         Modified := Item.ThreadItem.LastModified;
414                                         RangeStart := 0;
415                                         AdjustLen := 0;
416                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
417                                                 Item.State := gdsError;
418                                 end;
419 }
420
421                                 //********************
422                                 //offlaw.cgi\82Å\8eæ\93¾
423                                 //********************
424                                 FSessionID := '';
425                                 Synchronize(GetSessionID);
426                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID <> '') then begin
427                                         {$IFDEF DEBUG}
428                                         Writeln('offlaw.cgi\82Å\8eæ\93¾');
429                                         {$ENDIF}
430                                         ATitle := Item.ThreadItem.Title;
431                                         if ATitle = '' then
432                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
433                                         FMsg := '\81\9adat.gz\82ª\91\8dÝ\82µ\82È\82¢\82½\82ßofflaw.cgi\82ð\97\98\97p\82µ\82Ü\82· - [' + ATitle + ']';
434                                         FIcon := gmiWhat;
435                                         if Assigned(OnDownloadMsg) then
436                                                 Synchronize(FireDownloadMsg);
437                                         URL := Item.ThreadItem.GetOfflawCgiURL(FSessionID);
438                                         Modified := Item.ThreadItem.LastModified;
439                                         RangeStart := 0;
440                                         AdjustLen := 0;
441                                         if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then begin
442                                                 {$IFDEF DEBUG}
443                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
444                                                 {$ENDIF}
445                                                 Item.State := gdsError;
446
447                                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
448                                                         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';
449                                                         FIcon := gmiNG;
450                                                         if Assigned(OnDownloadMsg) then
451                                                                 Synchronize(FireDownloadMsg);
452                                                 end;
453
454                                         end else begin
455                                                 CgiStatus := ParseCgiStatus(Item.Content);
456                                                 {$IFDEF DEBUG}
457                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
458                                                 {$ENDIF}
459                                                 case CgiStatus.FStatus of
460                                                         gcsOK: begin
461                                                                 {$IFDEF DEBUG}
462                                                                 Writeln('CGIStatus: OK');
463                                                                 {$ENDIF}
464                                                                 Item.ResponseCode := 200;
465                                                                 Item.Content := DeleteStatusLine(Item.Content);
466                                                                 Item.ContentLength := CgiStatus.FSize;
467                                                         end;
468                                                         gcsINCR: begin
469                                                                 //\8d¡\82Í\82 \82è\82¦\82È\82¢
470                                                                 {$IFDEF DEBUG}
471                                                                 Writeln('CGIStatus: 206');
472                                                                 {$ENDIF}
473                                                                 Item.ResponseCode := 206;
474                                                                 Item.Content := DeleteStatusLine(Item.Content);
475                                                                 Item.ContentLength := CgiStatus.FSize;
476                                                         end;
477                                                         gcsERR: begin
478                                                                 {$IFDEF DEBUG}
479                                                                 Writeln('CGIStatus: 404(ERROR)');
480                                                                 {$ENDIF}
481                                                                 Item.ResponseCode := 404;
482                                                                 Item.State := gdsError;
483                                                                 Item.ErrText := CgiStatus.FErrText;
484                                                         end;
485                                                 end;
486                                                 if (Item.ResponseCode = 404) and (AnsiPos('\89ß\8b\8e\83\8d\83O\91q\8cÉ\82Å\94­\8c©', Item.ErrText) <> 0) then begin
487                                                         {$IFDEF DEBUG}
488                                                         Writeln('\89ß\8b\8e\83\8d\83O\8eæ\93¾');
489                                                         {$ENDIF}
490                                                         ATitle := Item.ThreadItem.Title;
491                                                         if ATitle = '' then
492                                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
493                                                         FMsg := '\81\9a\89ß\8b\8e\83\8d\83O\91q\8cÉ\82Å\94­\8c© - [' + ATitle + ']';
494                                                         FIcon := gmiWhat;
495                                                         if Assigned(OnDownloadMsg) then
496                                                                 Synchronize(FireDownloadMsg);
497                                                         Idx := Pos(' ', Item.ErrText);
498                                                         if Idx <> 0 then begin
499                                                                 URL := Copy(Item.ErrText, Idx + 1, Length(Item.ErrText));
500                                                                 if Pos( '://', URL ) = 0 then begin
501                                                                         if Pos('../', URL) = 1 then
502                                                                                 URL := Copy(URL, 4, MaxInt );
503                                                                         if Pos( '/', URL ) = 1 then
504                                                                                 URL := Copy( URL, 2, MaxInt );
505                                                                         URL := GikoSys.UrlToServer(Item.ThreadItem.ParentBoard.URL) + URL;
506                                                                 end;
507                                                                 Modified := Item.ThreadItem.LastModified;
508                                                                 RangeStart := 0;
509                                                                 AdjustLen := 0;
510                                                                 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
511                                                                         Item.State := gdsError;
512                                                                 {$IFDEF DEBUG}
513                                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
514                                                                 {$ENDIF}
515                                                         end;
516                                                 end;
517                                         end;
518                                 end else begin
519                                         if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID = '') then begin
520                                                 {$IFDEF DEBUG}
521                                                 Writeln('\83\8d\83O\83C\83\93\82³\82ê\82Ä\82È\82¢\82Ì\82Å\89ß\8b\8e\83\8d\83O\8eæ\93¾\95s\89Â');
522                                                 {$ENDIF}
523                                                 ATitle := Item.ThreadItem.Title;
524                                                 if ATitle = '' then
525                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
526                                                 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 + ']';
527                                                 FIcon := gmiSAD;
528                                                 if Assigned(OnDownloadMsg) then
529                                                         Synchronize(FireDownloadMsg);
530                                         end;
531                                 end;
532
533                                 case Item.ResponseCode of
534                                         200: Item.State := gdsComplete;
535                                         206: Item.State := gdsDiffComplete;
536                                         304: Item.State := gdsNotModify;
537                                         else
538                                                 Item.State := gdsError;
539                                 end;
540 {
541                                 //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
542                                 if (Item.ResponseCode in [200, 206]) and (Item.Content = '') then
543                                         Item.State := gdsError;
544                                 Item.LastModified := FIndy.Response.LastModified;
545                                 //\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é
546                                 Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
547                                 try
548                                         ResStream.Clear;
549                                         FIndy.Get(URL, ResStream);
550                                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
551                                         if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] <> #10) then begin
552                                                 //\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¾
553                                                 //\82±\82±\82Å\83\81\83b\83Z\81[\83W\95\\8e¦\83C\83x\83\93\83g
554                                                 //event
555                                                 FMsg := '\81u\82 \82Ú\81[\82ñ\81v\82ð\8c\9f\8fo\82µ\82½\82Ì\82Å\8dÄ\8eæ\93¾\82ð\8ds\82¢\82Ü\82·';
556                                                 if Assigned(OnDownloadMsg) then
557                                                         Synchronize(FireDownloadMsg);
558                                                 FIndy.Request.ContentRangeStart := 0;
559                                                 FIndy.Request.ContentRangeEnd := 0;
560                                                 AdjustLen := 0;
561                                                 ResStream.Clear;
562                                                 FIndy.Get(URL, ResStream);
563                                                 Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
564                                         end else if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] = #10) then begin
565                                                 //\8d·\95ª\8eæ\93¾\82©\82Â\82P\83o\83C\83g\96Ú\82ªLF\82Ì\8fê\8d\87\81i\90³\8fí\8eæ\93¾\81j\82Í\93ª\82ÌLF\82ð\8dí\8f\9c
566                                                 Item.Content := Copy(Item.Content, 2, Length(Item.Content));
567                                         end;
568                                 except
569                                         Item.State := gdsError;
570                                 end;
571                                 Item.ResponseCode := FIndy.ResponseCode;
572 }
573 {
574                                 try
575                                         ResStream.Clear;
576                                         FIndy.Get(URL, ResStream);
577                                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
578                                 except
579                                         Item.State := gdsError;
580                                 end;
581
582                                 CgiStatus := ParseCgiStatus(Item.Content);
583                                 if CgiStatus.FStatus = gcsOK then begin
584                                         if CgiStatus.FSize = 0 then
585                                                 Item.State := gdsNotModify
586                                         else if Item.DownType = gdtBoard then
587                                                 Item.State := gdsComplete
588                                         else
589                                                 Item.State := gdsDiffComplete;
590                                 end else if CgiStatus.FStatus = gcsINCR then begin
591                                         Item.State := gdsComplete;
592                                 end else if CgiStatus.FStatus = gcsERR then begin
593                                         Item.State := gdsError;
594                                         Item.ErrText := CgiStatus.FErrText;
595                                 end;
596                                 Item.ContentLength := CgiStatus.FSize;
597                                 }
598                         except
599                                 Item.State := gdsError;
600                         end;
601                         //Item.ResponseCode := FIndy.ResponseCode;
602                         if FAbort then
603                                 Item.State := gdsAbort;
604                 finally
605                         if Assigned(OnDownloadEnd) then
606                                 Synchronize(FireDownloadEnd);
607                         ResStream.Free;
608                 end;
609
610                 FIndy.Request.CustomHeaders.Clear;
611         FIndy.Request.RawHeaders.Clear;
612         FIndy.Request.Clear;
613         FIndy.Response.CustomHeaders.Clear;
614         FIndy.Response.RawHeaders.Clear;
615                 FIndy.Response.Clear;
616             FIndy.ProxyParams.Clear;
617
618                 if Terminated then Break;
619                 Suspend;
620         end;
621 end;
622
623 function TDownloadThread.CgiDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime): Boolean;
624 var
625         ResponseCode: Integer;
626         ResStream: TMemoryStream;
627 begin
628         ResponseCode := -1;
629         FIndy.Request.ContentRangeStart := 0;
630         FIndy.Request.ContentRangeEnd := 0;
631
632         FIndy.Request.CustomHeaders.Clear;
633         if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
634                 FIndy.Request.LastModified := modified - OffsetFromUTC;
635         end;
636         FIndy.Request.AcceptEncoding := '';
637         FIndy.Request.Accept := 'text/html';
638         ResStream := TMemoryStream.Create;
639         try
640                 try
641                         ResStream.Clear;
642                         {$IFDEF DEBUG}
643                         Writeln('URL: ' + URL);
644                         {$ENDIF}
645                         FIndy.Get(URL, ResStream);
646                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
647                         Item.LastModified := FIndy.Response.LastModified;
648                         //\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é
649                         Item.ContentLength := Length(Item.Content);
650                         //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
651                         if Item.Content = '' then
652                                 Result := False
653                         else
654                                 Result := True;
655                         {$IFDEF DEBUG}
656                         Writeln('\8eæ\93¾\82Å\97á\8aO\82È\82µ');
657                         {$ENDIF}
658                         ResponseCode := FIndy.ResponseCode;
659                 except
660                         on E: EIdSocketError do begin
661                                 Item.Content := '';
662                                 Item.LastModified := ZERO_DATE;
663                                 Item.ContentLength := 0;
664                                 Item.ErrText := E.Message;
665                                 Result := False;
666                                 ResponseCode := -1;
667                                 Screen.Cursor := crDefault;
668                         end;
669                         on E: EIdConnectException do begin
670                                 Item.Content := '';
671                                 Item.LastModified := ZERO_DATE;
672                                 Item.ContentLength := 0;
673                                 Item.ErrText := E.Message;
674                                 Result := False;
675                                 ResponseCode := -1;
676                                 Screen.Cursor := crDefault;
677                         end;
678                         on E: Exception do begin
679                                 {$IFDEF DEBUG}
680                                 Writeln('\8eæ\93¾\82Å\97á\8aO\82 \82è');
681                                 Writeln('E.Message: ' + E.Message);
682                                 {$ENDIF}
683                                 Item.Content := '';
684                                 Item.LastModified := ZERO_DATE;
685                                 Item.ContentLength := 0;
686                                 Item.ErrText := E.Message;
687                                 ResponseCode := FIndy.ResponseCode;
688                                 Result := False;
689                                 Screen.Cursor := crDefault;
690                         end;
691                 end;
692         finally
693                 if (Item.ContentLength = 0) and (ResponseCode = 206) then
694                         Item.ResponseCode := 304
695                 else
696                         Item.ResponseCode := ResponseCode;
697                 ResStream.Free;
698         end;
699 end;
700
701 function TDownloadThread.DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
702 var
703         ResponseCode: Integer;
704         ResStream: TMemoryStream;
705 begin
706         ResponseCode := -1;
707         if (ItemType = gdtThread) and (RangeStart > 0) then begin
708 //      if (ItemType = gdtThread) and (Item.ThreadItem.Size > 0) then begin
709 //              FIndy.Request.ContentRangeStart := Item.ThreadItem.Size + AdjustLen;
710                 FIndy.Request.ContentRangeStart := RangeStart + AdjustLen;
711                 FIndy.Request.ContentRangeEnd := 0;
712         end else begin
713                 FIndy.Request.ContentRangeStart := 0;
714                 FIndy.Request.ContentRangeEnd := 0;
715         end;
716
717         FIndy.Request.CustomHeaders.Clear;
718         FIndy.Request.CacheControl := 'no-cache';
719         FIndy.Request.CustomHeaders.Add('Pragma: no-cache');
720         if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
721                 FIndy.Request.LastModified := modified - OffsetFromUTC;
722                 //FIndy.Request.CustomHeaders.Add('If-Modified-Since: ' + RFC1123_Date(modified - OffsetFromUTC) + ' GMT');
723         end;
724 //      FIndy.Request.AcceptEncoding := 'gzip';
725         if RangeStart = 0 then
726                 FIndy.Request.AcceptEncoding := 'gzip'
727         else
728                 FIndy.Request.AcceptEncoding := '';
729         ResStream := TMemoryStream.Create;
730         try
731                 try
732                         ResStream.Clear;
733                         {$IFDEF DEBUG}
734                         Writeln('URL: ' + URL);
735                         {$ENDIF}
736                         FIndy.Get(URL, ResStream);
737                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
738                         Item.LastModified := FIndy.Response.LastModified;
739                         //\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é
740 //                      Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
741                         Item.ContentLength := Length(Item.Content) + AdjustLen;
742                         //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
743 //                      if (FIndy.ResponseCode in [200, 206]) and (Item.Content = '') then
744 //                              Result := False
745                         if Item.Content = '' then
746                                 Result := False
747                         else
748                                 Result := True;
749                         {$IFDEF DEBUG}
750                         Writeln('\8eæ\93¾\82Å\97á\8aO\82È\82µ');
751                         {$ENDIF}
752                         ResponseCode := FIndy.ResponseCode;
753                 except
754                         on E: EIdSocketError do begin
755                                 Item.Content := '';
756                                 Item.LastModified := ZERO_DATE;
757                                 Item.ContentLength := 0;
758                                 Item.ErrText := E.Message;
759                                 Result := False;
760                                 ResponseCode := -1;
761                                 Screen.Cursor := crDefault;
762                         end;
763                         on E: EIdConnectException do begin
764                                 Item.Content := '';
765                                 Item.LastModified := ZERO_DATE;
766                                 Item.ContentLength := 0;
767                                 Item.ErrText := E.Message;
768                                 Result := False;
769                                 ResponseCode := -1;
770                                 Screen.Cursor := crDefault;
771                         end;
772                         on E: Exception do begin
773                                 {$IFDEF DEBUG}
774                                 Writeln('\8eæ\93¾\82Å\97á\8aO\82 \82è');
775                                 Writeln('E.Message: ' + E.Message);
776                                 {$ENDIF}
777                                 Item.Content := '';
778                                 Item.LastModified := ZERO_DATE;
779                                 Item.ContentLength := 0;
780                                 Item.ErrText := E.Message;
781                                 ResponseCode := FIndy.ResponseCode;
782                                 Result := False;
783                                 Screen.Cursor := crDefault;
784                         end;
785                 end;
786         finally
787                 if (Item.ContentLength = 0) and (ResponseCode = 206) then
788                         Item.ResponseCode := 304
789                 else
790                         Item.ResponseCode := ResponseCode;
791                 ResStream.Free;
792         end;
793 end;
794
795 procedure TDownloadThread.FireDownloadEnd;
796 begin
797         OnDownloadEnd(self, Item);
798 end;
799
800 procedure TDownloadThread.FireDownloadMsg;
801 begin
802         OnDownloadMsg(Self, Item, FMsg, FIcon);
803 end;
804
805 procedure TDownloadThread.GetSessionID;
806 begin
807         FSessionID := GikoSys.Dolib.SessionID;
808 end;
809
810 procedure TDownloadThread.Abort;
811 begin
812         FAbort := True;
813         FIndy.DisconnectSocket;
814 end;
815
816 procedure TDownloadThread.WorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
817 begin
818         if Assigned(OnWorkBegin) then
819                 OnWorkBegin(Sender, AWorkMode, AWorkCountMax, FNumber, FDownloadTitle);
820 end;
821
822 procedure TDownloadThread.WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
823 begin
824         if Assigned(OnWorkEnd) then
825                 OnWorkEnd(Sender, AWorkMode, FNumber);
826 end;
827
828 procedure TDownloadThread.Work(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
829 begin
830         if Assigned(OnWork) then
831                 OnWork(Sender, AWorkMode, AWorkCount, FNumber);
832 end;
833
834 function TDownloadThread.ParseCgiStatus(Content: string): TCgiStatus;
835 var
836         StatusLine: string;
837         Line: string;
838         Idx: Integer;
839         Status: string;
840         Size: string;
841         Msg: string;
842 begin
843 // [+OK] \82Ì\8fê\8d\87\82Í\8d·\95ª
844 // [-INCR] (Incorrect)\82Ì\8fê\8d\87\82Í\82·\82×\82Ä\82Ì\83f\81[\83^
845 // [-ERR (\83e\83L\83X\83g)]\82Ì\8fê\8d\87\82Í\82È\82ñ\82©\83G\83\89\81[
846 // \97á\81F+OK 23094/512K
847 //               -INCR 23094/512K
848 //               -ERR \82»\82ñ\82È\94Â\82È\82¢\82Å\82·
849         Idx := AnsiPos(#10, Content);
850         StatusLine := Copy(Content, 0, Idx);
851
852         Idx := AnsiPos(' ', Content);
853         Status := Copy(StatusLine, 0, Idx - 1);
854         Line := Copy(StatusLine, Idx + 1, Length(StatusLine));
855
856 //      Idx := AnsiPos('/', Line);
857         if Trim(Status) = '-ERR' then
858                 Msg := Trim(Line)
859         else
860                 Size := Copy(Line, 0, Idx - 1);
861
862         if Trim(Status) = '+OK' then
863                 Result.FStatus := gcsOK
864         else if Trim(Status) = '-INCR' then
865                 Result.FStatus := gcsINCR
866         else if Trim(Status) = '-ERR' then begin
867                 Result.FStatus := gcsERR;
868                 Result.FErrText := Msg;
869                 Result.FSize := 0;
870                 Exit;
871         end else begin
872                 {$IFDEF DEBUG}
873                 Writeln(Status);
874                 {$ENDIF}
875                 Result.FStatus := gcsERR;
876                 Result.FErrText := '\83G\83\89\81[\82È\82ñ\82¾\82¯\82Ç\81A\82æ\82­\95ª\82©\82ç\82È\82¢\83G\83\89\81[';
877                 Result.FSize := 0;
878                 Exit;
879         end;
880
881         if GikoSys.IsNumeric(Size) then
882                 Result.FSize := StrToInt(Size)
883         else begin
884                 Result.FSize := 0;
885                 Result.FStatus := gcsERR;
886                 Result.FErrText := '\83X\83e\81[\83^\83X\89ð\90Í\8e¸\94s[' + StatusLine + ']';
887         end;
888 end;
889
890 //\8eè\94²\82«\82È\8f\88\97\9d\82Å1\8ds\96Ú\82ð\8fÁ\82·
891 function TDownloadThread.DeleteStatusLine(Content: string): string;
892 var
893         SList: TStringList;
894 begin
895         SList := TStringList.Create;
896         try
897                 SList.Text := Content;
898                 if SList.Count > 1 then
899                         SList.Delete(0);
900                 Result := SList.Text;
901         finally
902                 SList.Free;
903         end;
904 end;
905
906 procedure TDownloadItem.SaveListFile;
907 var
908         i: Integer;
909         index: Integer;
910         NewItem: TThreadItem;
911         NumCount: Integer;
912         Body: TStringList;
913         Rec: TSubjectRec;
914         function MakeThreadCallBack(
915                 inInstance      : DWORD;        // TBoardItem \82Ì\83C\83\93\83X\83^\83\93\83X
916                 inURL                           : PChar;        // \83X\83\8c\83b\83h\82Ì URL
917                 inTitle                 : PChar;        // \83X\83\8c\83^\83C
918                 inCount                 : DWORD         // \83\8c\83X\82Ì\90\94
919         ) : Boolean; stdcall;           // \97ñ\8b\93\82ð\91±\82¯\82é\82È\82ç True
920         var
921                 _ThreadItem     : TThreadItem;  // '_' \82Í\83N\83\89\83X\82Ì\83v\83\8d\83p\83e\83B\82Æ\82©\82Ô\82Á\82Ä\82é\82Ì\82Å
922                 boardItem               : TBoard;
923         begin
924                 Result          := True;
925                 boardItem       := TBoard( inInstance );
926
927                 boardItem.IntData := boardItem.IntData + 1;
928                 index := boardItem.GetIndexFromURL( string( inURL ) );
929                 if index = -1 then begin
930                         //\90V\82µ\82¢\83X\83\8c\83b\83h
931                         _ThreadItem := TThreadItem.Create( boardItem.BoardPlugIn, string( inURL ) );
932
933                         _ThreadItem.Title                                       := string( inTitle );
934                         _ThreadItem.AllResCount         := inCount;
935                         _ThreadItem.ParentBoard         := Board;
936                         _ThreadItem.No                                          := boardItem.IntData;
937                         _ThreadItem.RoundDate           := ZERO_DATE;
938                         _ThreadItem.LastModified        := ZERO_DATE;
939                         _ThreadItem.AgeSage                             := gasNew;
940                         boardItem.Add(_ThreadItem);
941                 end else begin
942                         if boardItem.Items[index].No > boardItem.IntData then
943                                 boardItem.Items[index].AgeSage := gasAge
944                         else if boardItem.Items[index].AllResCount < inCount then
945                                 boardItem.Items[index].AgeSage := gasSage
946                         else
947                                 boardItem.Items[index].AgeSage := gasNone;
948
949                         boardItem.Items[index].No                                               := boardItem.IntData;
950                         boardItem.Items[index].AllResCount      := inCount;
951                 end;
952         end;
953 begin
954         //Board.ListData := TList.Create;
955         Body := TStringList.Create;
956         try
957                 //\83_\83E\83\93\83\8d\81[\83h\93ú\8e\9e\90Ý\92è\81i\83\8d\81[\83J\83\8b\93ú\8e\9e\81j
958                 Board.RoundDate := Now;
959                 //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
960                 Board.LastModified := LastModified;
961                 for i := Board.Count - 1 downto 0 do
962                         Board.Items[i].AgeSage := gasNull;
963
964                 if Board.IsBoardPlugInAvailable then begin
965                         // \90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
966                         // \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Á
967                         // \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¬
968                         Board.IntData := 0;
969                         Board.BoardPlugIn.EnumThread( DWORD( Board ), @MakeThreadCallBack );
970
971             //\8cÃ\82¢\83\8a\83X\83g\82É\82µ\82©\82È\82¢\82â\82Â\82ç\82ð\8dí\8f\9c
972                         for i := Board.Count - 1 downto 0 do begin
973                                 if( Board.Items[i].AgeSage = gasNull )and not (Board.Items[i].IsLogFile) then
974                                         Board.Delete(i);
975                         end;
976
977                         // \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Á
978                         for i := 0 to Board.Count - 1 do begin
979                                 if(Board.Items[i].AgeSage = gasNull) and (Board.Items[i].IsLogFile) then begin
980                                         Board.IntData := Board.IntData + 1;
981                                         Board.Items[i].No                                               := Board.IntData;
982                                         Board.Items[i].AllResCount      := Board.Items[i].Count;
983                                         Board.Items[i].NewResCount      := 0;
984                                         Board.Items[i].AgeSage                  := gasNone;
985                                 end;
986                         end;
987                 end else begin
988                         //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
989                         //\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Á
990                         //\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¬
991                         Body.Text := Content;
992                         NumCount := 0;
993                         for i := 0 to Body.Count - 1 do begin
994                                 Rec := GikoSys.DivideSubject(Body[i]);
995                                 Rec.FFileName := Trim(Rec.FFileName);
996                                 if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
997                                 Inc(NumCount);
998                                 index := Board.GetIndexFromFileName(Rec.FFileName);
999                                 if index = -1 then begin
1000                                         //\90V\82µ\82¢\83X\83\8c\83b\83h
1001                                         NewItem := TThreadItem.Create(
1002                         nil, GikoSys.Get2chBoard2ThreadURL( Board, ChangeFileExt( Rec.FFileName, '' ) ) );
1003                                         NewItem.Title := Rec.FTitle;
1004                                         NewItem.AllResCount := Rec.FCount;
1005                                         NewItem.ParentBoard := Board;
1006                                         NewItem.No := NumCount;
1007                                         NewItem.RoundDate := ZERO_DATE;
1008                                         NewItem.LastModified := ZERO_DATE;
1009                                         NewItem.AgeSage := gasNew;
1010                                         Board.Add(NewItem);
1011                                 end else begin
1012                                         if Board.Items[index].No > NumCount then
1013                                                 Board.Items[index].AgeSage := gasAge
1014                                         else if Board.Items[index].AllResCount < Rec.FCount then
1015                                                 Board.Items[index].AgeSage := gasSage
1016                                         else
1017                                                 Board.Items[index].AgeSage := gasNone;
1018
1019                                         Board.Items[index].No := NumCount;
1020                                         Board.Items[index].AllResCount := Rec.FCount;
1021                                 end;
1022                         end;
1023                         //\8cÃ\82¢\83\8a\83X\83g\82Ì\8dí\8f\9c
1024                         for i := Board.Count - 1 downto 0 do begin
1025                                 if( Board.Items[i].AgeSage = gasNull )and not (Board.Items[i].IsLogFile) then
1026                                         Board.Delete(i);
1027                         end;
1028
1029                         //\90V\82µ\82¢\83\8a\83X\83g\82É\96³\82©\82Á\82½\83A\83C\83e\83\80\82Ì\8dX\90V
1030                         for i := 0 to Board.Count - 1 do begin
1031                                 if( Board.Items[i].AgeSage = gasNull )and (Board.Items[i].IsLogFile) then begin
1032                                         inc(NumCount);
1033                                         Board.Items[i].No := NumCount;
1034                                         Board.Items[i].AllResCount := Board.Items[i].Count;
1035                                         Board.Items[i].NewResCount := 0;
1036                                         Board.Items[i].AgeSage := gasNone;
1037                                 end;
1038                         end;
1039                         //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
1040                         GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
1041                         Body.SaveToFile(Board.GetSubjectFileName);
1042                 end;
1043         finally
1044                 Body.Free;
1045         end;
1046
1047
1048 end;
1049
1050 {procedure TDownloadItem.SaveListFile;
1051 var
1052         i: Integer;
1053         index: Integer;
1054         NewItem: TThreadItem;
1055         NewList: TList;
1056 //      SaveCount: Integer;
1057         NumCount: Integer;
1058         Body: TStringList;
1059         Rec: TSubjectRec;
1060 begin
1061         NewList := TList.Create;
1062         Body := TStringList.Create;
1063         try
1064                 //\8f\84\89ñ\93ú\8e\9e\90Ý\92è
1065                 Board.RoundDate := Now;
1066                 //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
1067                 Board.LastModified := LastModified;
1068
1069                 //\83\8a\83X\83g\95Û\91\8c\8f\90\94\8eæ\93¾
1070                 //SaveCount := MaxInt;
1071
1072                 //\8cÃ\82¢\83\8a\83X\83g\82©\82ç\83\8d\83O\96³\82µ\83A\83C\83e\83\80\82ð\8dí\8f\9c
1073                 for i := Board.Count - 1 downto 0 do
1074                         if not Board.Items[i].IsLogFile then
1075                                 Board.Delete(i);
1076
1077                 //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
1078                 //\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Á
1079                 //\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¬
1080                 Body.Text := Content;
1081 //              Loop := Min(Body.Count, SaveCount);
1082                 NumCount := 0;
1083 //              for i := 0 to Loop - 1 do begin
1084                 for i := 0 to Body.Count - 1 do begin
1085                         if i = 0 then Continue; //\82P\8ds\96Ú\82Í\83X\83e\81[\83^\83X\8ds\82Ì\82½\82ß\8f\88\97\9d\82È\82µ
1086
1087                         Rec := GikoSys.DivideSubject(Body[i]);
1088                         if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
1089                         Inc(NumCount);
1090                         index := Board.GetIndex(Rec.FFileName);
1091                         if index = -1 then begin
1092                                 NewItem := TThreadItem.Create;
1093                                 NewItem.FileName := Rec.FFileName;
1094                                 NewItem.Title := Rec.FTitle;
1095                                 NewItem.Count := Rec.FCount;
1096                                 NewItem.ParentBoard := Board;
1097                                 NewItem.No := NumCount;
1098                                 NewItem.RoundDate := ZERO_DATE;
1099                                 NewItem.LastModified := ZERO_DATE;
1100                                 NewList.Add(NewItem);
1101                         end else begin
1102                                 //Board.Items[index].Count := Count;
1103                                 Board.Items[index].No := NumCount;
1104                                 NewList.Add(Board.Items[index]);
1105                                 Board.DeleteList(index);
1106                         end;
1107                 end;
1108
1109                 //\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Á
1110                 for i := 0 to Board.Count - 1 do begin
1111                         inc(NumCount);
1112                         Board.Items[i].No := NumCount;
1113                         NewList.Add(Board.Items[i]);
1114                 end;
1115
1116                 //\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
1117                 for i := Board.Count - 1 downto 0 do
1118                         Board.DeleteList(i);
1119
1120                 //\90V\82µ\82¢\83\8a\83X\83g\82ð\83{\81[\83h\83I\83u\83W\83F\83N\83g\82É\92Ç\89Á
1121                 for i := 0 to NewList.Count - 1 do
1122                         Board.Add(TThreadItem(NewList[i]));
1123
1124                 //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
1125 //              GikoSys.ForceDirectoriesEx(GikoSys.GetLogDir + Board.BBSID);
1126 //              Body.SaveToFile(GikoSys.GetSubjectFileName(Board.BBSID));
1127                 GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
1128                 Body.SaveToFile(Board.GetSubjectFileName);
1129         finally
1130                 Body.Free;
1131                 NewList.Free;
1132         end;
1133 end;
1134 }
1135 procedure TDownloadItem.SaveItemFile;
1136 var
1137         Body: TStringList;
1138         Cnt: Integer;
1139         OldCnt: Integer;
1140         FileName: string;
1141         ini: TMemIniFile;
1142         Res: TResRec;
1143         NewRes: Integer;
1144     finish : Boolean;
1145     loopCnt : Integer;
1146 begin
1147         FileName := ThreadItem.GetThreadFileName;
1148
1149         if not ThreadItem.IsBoardPlugInAvailable then begin
1150                 if Trim(Content) = '' then
1151                         Exit;
1152                 GikoSys.ForceDirectoriesEx(ExtractFilePath(FileName));
1153
1154         //      Cnt := 0;
1155                 Body := TStringList.Create;
1156         NewRes := 0;
1157         OldCnt := 0;
1158                 try
1159         //              if FileExists(FileName) and (ResponseCode = 206) then begin
1160                         if FileExists(FileName) and (State = gdsDiffComplete) then begin
1161         //                      Body.Text := Content;
1162         //                      if Body.Count > 0 then
1163         //                              Body.Delete(0);
1164         //                      Content := Body.Text;
1165                 loopCnt := 10;
1166                                 repeat
1167                     finish := true;
1168                         try
1169                                                 Body.LoadFromFile(FileName);
1170                                                 OldCnt := Body.Count;
1171                                                 Body.Text := Body.Text + Content;
1172                                                 Body.SaveToFile(FileName);
1173                                                 NewRes := Body.Count - OldCnt;
1174                         except
1175                                 on E:EFOpenError do begin
1176                             sleep(10);
1177                                 finish := false;
1178                             Dec(loopCnt);
1179                         end;
1180                         end;
1181                 until finish and ( loopCnt > 0 );
1182                                 //Cnt := Body.Count;
1183                         end else begin
1184                                 Body.Text := Content;
1185         //                      if Body.Count > 0 then
1186         //                              Body.Delete(0);
1187                                 Body.SaveToFile(FileName);
1188
1189                                 if ThreadItem.Title = '' then begin
1190                                         Res := GikoSys.DivideStrLine(Body[0]);
1191                                         ThreadItem.Title := Res.FTitle;
1192                                 end;
1193                                 ThreadItem.Size := 0;
1194                                 //ThreadItem.Count := 0;
1195                                 ThreadItem.AllResCount := 0;
1196                                 ThreadItem.NewResCount := 0;
1197                                 OldCnt := 0;
1198                                 NewRes := Body.Count;
1199                                 //Cnt := Body.Count;
1200                         end;
1201                         Cnt := Body.Count;
1202                 finally
1203                         Body.Free;
1204                 end;
1205         
1206                 ThreadItem.Size := ThreadItem.Size + ContentLength;
1207                 ThreadItem.LastModified := LastModified;
1208                 ThreadItem.Count := Cnt;
1209                 //ThreadItem.AllResCount := Cnt;
1210                 ThreadItem.NewResCount := NewRes;
1211                 ThreadItem.NewReceive := OldCnt + 1;
1212         end;
1213     ThreadItem.AllResCount := ThreadItem.Count;
1214         ThreadItem.IsLogFile := True;
1215         ThreadItem.RoundDate := Now;
1216         ThreadItem.UnRead := True;
1217         ThreadItem.ParentBoard.UnRead := ThreadItem.ParentBoard.UnRead + 1;
1218 //      if ThreadItem.RoundNo = 6 then
1219 //              ThreadItem.RoundNo := 0;
1220
1221         //\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
1222         //\90³\8fí\8fI\97¹\8e\9e\82É\82Í\8dí\8f\9c
1223         //\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
1224         ini := TMemIniFile.Create(ChangeFileExt(FileName, '.tmp'));
1225         try
1226                 ini.WriteDateTime('Setting', 'RoundDate', ThreadItem.RoundDate);
1227                 ini.WriteDateTime('Setting', 'LastModified', ThreadItem.LastModified);
1228                 ini.WriteInteger('Setting', 'Size', ThreadItem.Size);
1229                 ini.WriteInteger('Setting', 'Count', ThreadItem.Count);
1230                 ini.WriteInteger('Setting', 'AllResCount', ThreadItem.AllResCount);
1231                 ini.WriteInteger('Setting', 'NewResCount', ThreadItem.NewResCount);
1232                 ini.WriteInteger('Setting', 'NewReceive', ThreadItem.NewReceive);
1233 //              ini.WriteInteger('Setting', 'RoundNo', ThreadItem.RoundNo);
1234                 ini.WriteBool('Setting', 'Round', ThreadItem.Round);
1235                 ini.WriteBool('Setting', 'UnRead', ThreadItem.UnRead);
1236         ini.UpdateFile;
1237         finally
1238                 ini.Free;
1239         end;
1240 end;
1241
1242 end.