OSDN Git Service

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