OSDN Git Service

・今まで 1 つ固定であった BBS が複数持てるようになった。
[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) = 1 then
458                                                                         URL := Copy(URL, 4, Length(URL));
459                                                                 URL := GikoSys.UrlToServer(Item.ThreadItem.ParentBoard.URL) + URL;
460                                                                 Modified := Item.ThreadItem.LastModified;
461                                                                 RangeStart := 0;
462                                                                 AdjustLen := 0;
463                                                                 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
464                                                                         Item.State := gdsError;
465                                                                 {$IFDEF DEBUG}
466                                                                 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
467                                                                 {$ENDIF}
468                                                         end;
469                                                 end;
470                                         end;
471                                 end else begin
472                                         if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID = '') then begin
473                                                 {$IFDEF DEBUG}
474                                                 Writeln('\83\8d\83O\83C\83\93\82³\82ê\82Ä\82È\82¢\82Ì\82Å\89ß\8b\8e\83\8d\83O\8eæ\93¾\95s\89Â');
475                                                 {$ENDIF}
476                                                 ATitle := Item.ThreadItem.Title;
477                                                 if ATitle = '' then
478                                                         ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
479                                                 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 + ']';
480                                                 FIcon := gmiSAD;
481                                                 if Assigned(OnDownloadMsg) then
482                                                         Synchronize(FireDownloadMsg);
483                                         end;
484                                 end;
485
486                                 {$IFDEF DEBUG}
487                                 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
488                                         ATitle := Item.ThreadItem.Title;
489                                         if ATitle = '' then
490                                                 ATitle := '\81i\96¼\8fÌ\95s\96¾\81j';
491                                         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 + ']';
492                                         FIcon := gmiWhat;
493                                         if Assigned(OnDownloadMsg) then
494                                                 Synchronize(FireDownloadMsg);
495                                         URL := 'http://www.google.co.jp/search?q=cache:' + Item.ThreadItem.URL;
496                                         URL := StringReplace( URL, 'l50', '', [rfReplaceAll] );
497                                         Modified := Item.ThreadItem.LastModified;
498                                         Repeat
499                                                 if not CgiDownload(Item.DownType, URL, Modified) then
500                                                         Item.State := gdsError;
501                                                 URL := FIndy.Response.Location;
502                                         Until Item.ResponseCode <> 301;
503                                         if Item.ResponseCode = 200 then begin
504                                                 foundPos := Pos( '<dt>', Item.Content ) + Length( '<dt>' );
505                                                 Item.Content := Copy( Item.Content, foundPos, Length( Item.Content ) );
506                                                 foundPos := Pos( '</dl>', Item.Content );
507                                                 If foundPos > 0 Then
508                                                         Item.Content := Copy( Item.Content, 1, foundPos - 1 );
509                                                 Item.Content := StringReplace( Item.Content, '<dt>', '<>' + #13#10, [rfReplaceAll] );
510                                                 Item.Content := StringReplace( Item.Content, '<a href="mailto:', '', [rfReplaceAll] );
511                                                 Item.Content := StringReplace( Item.Content, '"><b>', '<>', [rfReplaceAll] );
512                                                 Item.Content := StringReplace( Item.Content, '<b>', '<>', [rfReplaceAll] );
513                                                 Item.Content := StringReplace( Item.Content, '</b></a>', '<>', [rfReplaceAll] );
514                                                 Item.Content := StringReplace( Item.Content, '</b>', '<>', [rfReplaceAll] );
515                                                 Item.Content := StringReplace( Item.Content, '<dd>', '<>', [rfReplaceAll] );
516                                         end;
517                                 end;
518                                 {$ENDIF}
519
520                                 case Item.ResponseCode of
521                                         200: Item.State := gdsComplete;
522                                         206: Item.State := gdsDiffComplete;
523                                         304: Item.State := gdsNotModify;
524                                         else
525                                                 Item.State := gdsError;
526                                 end;
527 {
528                                 //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
529                                 if (Item.ResponseCode in [200, 206]) and (Item.Content = '') then
530                                         Item.State := gdsError;
531                                 Item.LastModified := FIndy.Response.LastModified;
532                                 //\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é
533                                 Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
534                                 try
535                                         ResStream.Clear;
536                                         FIndy.Get(URL, ResStream);
537                                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
538                                         if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] <> #10) then begin
539                                                 //\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¾
540                                                 //\82±\82±\82Å\83\81\83b\83Z\81[\83W\95\\8e¦\83C\83x\83\93\83g
541                                                 //event
542                                                 FMsg := '\81u\82 \82Ú\81[\82ñ\81v\82ð\8c\9f\8fo\82µ\82½\82Ì\82Å\8dÄ\8eæ\93¾\82ð\8ds\82¢\82Ü\82·';
543                                                 if Assigned(OnDownloadMsg) then
544                                                         Synchronize(FireDownloadMsg);
545                                                 FIndy.Request.ContentRangeStart := 0;
546                                                 FIndy.Request.ContentRangeEnd := 0;
547                                                 AdjustLen := 0;
548                                                 ResStream.Clear;
549                                                 FIndy.Get(URL, ResStream);
550                                                 Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
551                                         end else 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Ì\8fê\8d\87\81i\90³\8fí\8eæ\93¾\81j\82Í\93ª\82ÌLF\82ð\8dí\8f\9c
553                                                 Item.Content := Copy(Item.Content, 2, Length(Item.Content));
554                                         end;
555                                 except
556                                         Item.State := gdsError;
557                                 end;
558                                 Item.ResponseCode := FIndy.ResponseCode;
559 }
560 {
561                                 try
562                                         ResStream.Clear;
563                                         FIndy.Get(URL, ResStream);
564                                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
565                                 except
566                                         Item.State := gdsError;
567                                 end;
568
569                                 CgiStatus := ParseCgiStatus(Item.Content);
570                                 if CgiStatus.FStatus = gcsOK then begin
571                                         if CgiStatus.FSize = 0 then
572                                                 Item.State := gdsNotModify
573                                         else if Item.DownType = gdtBoard then
574                                                 Item.State := gdsComplete
575                                         else
576                                                 Item.State := gdsDiffComplete;
577                                 end else if CgiStatus.FStatus = gcsINCR then begin
578                                         Item.State := gdsComplete;
579                                 end else if CgiStatus.FStatus = gcsERR then begin
580                                         Item.State := gdsError;
581                                         Item.ErrText := CgiStatus.FErrText;
582                                 end;
583                                 Item.ContentLength := CgiStatus.FSize;
584                                 }
585                         except
586                                 Item.State := gdsError;
587                         end;
588                         //Item.ResponseCode := FIndy.ResponseCode;
589                         if FAbort then
590                                 Item.State := gdsAbort;
591                 finally
592                         if Assigned(OnDownloadEnd) then
593                                 Synchronize(FireDownloadEnd);
594                         ResStream.Free;
595                 end;
596                 if Terminated then Break;
597                 Suspend;
598         end;
599 end;
600
601 function TDownloadThread.CgiDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime): Boolean;
602 var
603         ResponseCode: Integer;
604         ResStream: TMemoryStream;
605 begin
606         ResponseCode := -1;
607         FIndy.Request.ContentRangeStart := 0;
608         FIndy.Request.ContentRangeEnd := 0;
609
610         FIndy.Request.CustomHeaders.Clear;
611         if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
612                 FIndy.Request.LastModified := modified - OffsetFromUTC;
613         end;
614         FIndy.Request.AcceptEncoding := '';
615         FIndy.Request.Accept := 'text/html';
616         ResStream := TMemoryStream.Create;
617         try
618                 try
619                         ResStream.Clear;
620                         {$IFDEF DEBUG}
621                         Writeln('URL: ' + URL);
622                         {$ENDIF}
623                         FIndy.Get(URL, ResStream);
624                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
625                         Item.LastModified := FIndy.Response.LastModified;
626                         //\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é
627                         Item.ContentLength := Length(Item.Content);
628                         //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
629                         if Item.Content = '' then
630                                 Result := False
631                         else
632                                 Result := True;
633                         {$IFDEF DEBUG}
634                         Writeln('\8eæ\93¾\82Å\97á\8aO\82È\82µ');
635                         {$ENDIF}
636                         ResponseCode := FIndy.ResponseCode;
637                 except
638                         on E: EIdSocketError do begin
639                                 Item.Content := '';
640                                 Item.LastModified := ZERO_DATE;
641                                 Item.ContentLength := 0;
642                                 Item.ErrText := E.Message;
643                                 Result := False;
644                                 ResponseCode := -1;
645                                 Screen.Cursor := crDefault;
646                         end;
647                         on E: EIdConnectException do begin
648                                 Item.Content := '';
649                                 Item.LastModified := ZERO_DATE;
650                                 Item.ContentLength := 0;
651                                 Item.ErrText := E.Message;
652                                 Result := False;
653                                 ResponseCode := -1;
654                                 Screen.Cursor := crDefault;
655                         end;
656                         on E: Exception do begin
657                                 {$IFDEF DEBUG}
658                                 Writeln('\8eæ\93¾\82Å\97á\8aO\82 \82è');
659                                 Writeln('E.Message: ' + E.Message);
660                                 {$ENDIF}
661                                 Item.Content := '';
662                                 Item.LastModified := ZERO_DATE;
663                                 Item.ContentLength := 0;
664                                 Item.ErrText := E.Message;
665                                 ResponseCode := FIndy.ResponseCode;
666                                 Result := False;
667                                 Screen.Cursor := crDefault;
668                         end;
669                 end;
670         finally
671                 if (Item.ContentLength = 0) and (ResponseCode = 206) then
672                         Item.ResponseCode := 304
673                 else
674                         Item.ResponseCode := ResponseCode;
675                 ResStream.Free;
676         end;
677 end;
678
679 function TDownloadThread.DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
680 var
681         ResponseCode: Integer;
682         ResStream: TMemoryStream;
683 begin
684         ResponseCode := -1;
685         if (ItemType = gdtThread) and (RangeStart > 0) then begin
686 //      if (ItemType = gdtThread) and (Item.ThreadItem.Size > 0) then begin
687 //              FIndy.Request.ContentRangeStart := Item.ThreadItem.Size + AdjustLen;
688                 FIndy.Request.ContentRangeStart := RangeStart + AdjustLen;
689                 FIndy.Request.ContentRangeEnd := 0;
690         end else begin
691                 FIndy.Request.ContentRangeStart := 0;
692                 FIndy.Request.ContentRangeEnd := 0;
693         end;
694
695         FIndy.Request.CustomHeaders.Clear;
696         FIndy.Request.CacheControl := 'no-cache';
697         FIndy.Request.CustomHeaders.Add('Pragma: no-cache');
698         if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
699                 FIndy.Request.LastModified := modified - OffsetFromUTC;
700                 //FIndy.Request.CustomHeaders.Add('If-Modified-Since: ' + RFC1123_Date(modified - OffsetFromUTC) + ' GMT');
701         end;
702 //      FIndy.Request.AcceptEncoding := 'gzip';
703         if RangeStart = 0 then
704                 FIndy.Request.AcceptEncoding := 'gzip'
705         else
706                 FIndy.Request.AcceptEncoding := '';
707         ResStream := TMemoryStream.Create;
708         try
709                 try
710                         ResStream.Clear;
711                         {$IFDEF DEBUG}
712                         Writeln('URL: ' + URL);
713                         {$ENDIF}
714                         FIndy.Get(URL, ResStream);
715                         Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
716                         Item.LastModified := FIndy.Response.LastModified;
717                         //\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é
718 //                      Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
719                         Item.ContentLength := Length(Item.Content) + AdjustLen;
720                         //\96³\82¢\82Æ\8ev\82¤\82¯\82Ç\81B\81B\81B
721 //                      if (FIndy.ResponseCode in [200, 206]) and (Item.Content = '') then
722 //                              Result := False
723                         if Item.Content = '' then
724                                 Result := False
725                         else
726                                 Result := True;
727                         {$IFDEF DEBUG}
728                         Writeln('\8eæ\93¾\82Å\97á\8aO\82È\82µ');
729                         {$ENDIF}
730                         ResponseCode := FIndy.ResponseCode;
731                 except
732                         on E: EIdSocketError do begin
733                                 Item.Content := '';
734                                 Item.LastModified := ZERO_DATE;
735                                 Item.ContentLength := 0;
736                                 Item.ErrText := E.Message;
737                                 Result := False;
738                                 ResponseCode := -1;
739                                 Screen.Cursor := crDefault;
740                         end;
741                         on E: EIdConnectException do begin
742                                 Item.Content := '';
743                                 Item.LastModified := ZERO_DATE;
744                                 Item.ContentLength := 0;
745                                 Item.ErrText := E.Message;
746                                 Result := False;
747                                 ResponseCode := -1;
748                                 Screen.Cursor := crDefault;
749                         end;
750                         on E: Exception do begin
751                                 {$IFDEF DEBUG}
752                                 Writeln('\8eæ\93¾\82Å\97á\8aO\82 \82è');
753                                 Writeln('E.Message: ' + E.Message);
754                                 {$ENDIF}
755                                 Item.Content := '';
756                                 Item.LastModified := ZERO_DATE;
757                                 Item.ContentLength := 0;
758                                 Item.ErrText := E.Message;
759                                 ResponseCode := FIndy.ResponseCode;
760                                 Result := False;
761                                 Screen.Cursor := crDefault;
762                         end;
763                 end;
764         finally
765                 if (Item.ContentLength = 0) and (ResponseCode = 206) then
766                         Item.ResponseCode := 304
767                 else
768                         Item.ResponseCode := ResponseCode;
769                 ResStream.Free;
770         end;
771 end;
772
773 procedure TDownloadThread.FireDownloadEnd;
774 begin
775         OnDownloadEnd(self, Item);
776 end;
777
778 procedure TDownloadThread.FireDownloadMsg;
779 begin
780         OnDownloadMsg(Self, Item, FMsg, FIcon);
781 end;
782
783 procedure TDownloadThread.GetSessionID;
784 begin
785         FSessionID := GikoSys.Dolib.SessionID;
786 end;
787
788 procedure TDownloadThread.Abort;
789 begin
790         FAbort := True;
791         FIndy.DisconnectSocket;
792 end;
793
794 procedure TDownloadThread.WorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
795 begin
796         if Assigned(OnWorkBegin) then
797                 OnWorkBegin(Sender, AWorkMode, AWorkCountMax, FNumber);
798 end;
799
800 procedure TDownloadThread.WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
801 begin
802         if Assigned(OnWorkEnd) then
803                 OnWorkEnd(Sender, AWorkMode, FNumber);
804 end;
805
806 procedure TDownloadThread.Work(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
807 begin
808         if Assigned(OnWork) then
809                 OnWork(Sender, AWorkMode, AWorkCount, FNumber);
810 end;
811
812 function TDownloadThread.ParseCgiStatus(Content: string): TCgiStatus;
813 var
814         StatusLine: string;
815         Line: string;
816         Idx: Integer;
817         Status: string;
818         Size: string;
819         Msg: string;
820 begin
821 // [+OK] \82Ì\8fê\8d\87\82Í\8d·\95ª
822 // [-INCR] (Incorrect)\82Ì\8fê\8d\87\82Í\82·\82×\82Ä\82Ì\83f\81[\83^
823 // [-ERR (\83e\83L\83X\83g)]\82Ì\8fê\8d\87\82Í\82È\82ñ\82©\83G\83\89\81[
824 // \97á\81F+OK 23094/512K
825 //               -INCR 23094/512K
826 //               -ERR \82»\82ñ\82È\94Â\82È\82¢\82Å\82·
827         Idx := AnsiPos(#10, Content);
828         StatusLine := Copy(Content, 0, Idx);
829
830         Idx := AnsiPos(' ', Content);
831         Status := Copy(StatusLine, 0, Idx - 1);
832         Line := Copy(StatusLine, Idx + 1, Length(StatusLine));
833
834 //      Idx := AnsiPos('/', Line);
835         if Trim(Status) = '-ERR' then
836                 Msg := Trim(Line)
837         else
838                 Size := Copy(Line, 0, Idx - 1);
839
840         if Trim(Status) = '+OK' then
841                 Result.FStatus := gcsOK
842         else if Trim(Status) = '-INCR' then
843                 Result.FStatus := gcsINCR
844         else if Trim(Status) = '-ERR' then begin
845                 Result.FStatus := gcsERR;
846                 Result.FErrText := Msg;
847                 Result.FSize := 0;
848                 Exit;
849         end else begin
850                 {$IFDEF DEBUG}
851                 Writeln(Status);
852                 {$ENDIF}
853                 Result.FStatus := gcsERR;
854                 Result.FErrText := '\83G\83\89\81[\82È\82ñ\82¾\82¯\82Ç\81A\82æ\82­\95ª\82©\82ç\82È\82¢\83G\83\89\81[';
855                 Result.FSize := 0;
856                 Exit;
857         end;
858
859         if GikoSys.IsNumeric(Size) then
860                 Result.FSize := StrToInt(Size)
861         else begin
862                 Result.FSize := 0;
863                 Result.FStatus := gcsERR;
864                 Result.FErrText := '\83X\83e\81[\83^\83X\89ð\90Í\8e¸\94s[' + StatusLine + ']';
865         end;
866 end;
867
868 //\8eè\94²\82«\82È\8f\88\97\9d\82Å1\8ds\96Ú\82ð\8fÁ\82·
869 function TDownloadThread.DeleteStatusLine(Content: string): string;
870 var
871         SList: TStringList;
872 begin
873         SList := TStringList.Create;
874         try
875                 SList.Text := Content;
876                 if SList.Count > 1 then
877                         SList.Delete(0);
878                 Result := SList.Text;
879         finally
880                 SList.Free;
881         end;
882 end;
883
884 procedure TDownloadItem.SaveListFile;
885 var
886         i: Integer;
887         index: Integer;
888         NewItem: TThreadItem;
889 //      SaveCount: Integer;
890         NumCount: Integer;
891         Body: TStringList;
892         Rec: TSubjectRec;
893         function MakeThreadCallBack(
894                 inInstance      : DWORD;        // TBoardItem \82Ì\83C\83\93\83X\83^\83\93\83X
895                 inURL                           : PChar;        // \83X\83\8c\83b\83h\82Ì URL
896                 inTitle                 : PChar;        // \83X\83\8c\83^\83C
897                 inCount                 : DWORD         // \83\8c\83X\82Ì\90\94
898         ) : Boolean; stdcall;           // \97ñ\8b\93\82ð\91±\82¯\82é\82È\82ç True
899         var
900                 threadItem      : TThreadItem;
901                 boardItem               : TBoard;
902         begin
903                 Result          := True;
904                 boardItem       := TBoard( inInstance );
905
906                 boardItem.IntData := boardItem.IntData + 1;
907                 index := boardItem.GetIndexFromURL( string( inURL ) );
908                 if index = -1 then begin
909                         //\90V\82µ\82¢\83X\83\8c\83b\83h
910                         threadItem := TThreadItem.Create( boardItem.BoardPlugIn, string( inURL ) );
911
912                         threadItem.Title                                := string( inTitle );
913 //                              threadItem.Count := inCount;
914                         threadItem.AllResCount  := inCount;
915                         threadItem.ParentBoard  := Board;
916                         threadItem.No                                           := boardItem.IntData;
917                         threadItem.RoundDate            := ZERO_DATE;
918                         threadItem.LastModified := ZERO_DATE;
919                         threadItem.AgeSage                      := gasNew;
920                         boardItem.ListData.Add( threadItem );
921                 end else begin
922                         //boardItem.Items[index].Count := Count;
923                         //boardItem.Items[index].Count := Rec.FCount;
924                         if boardItem.Items[index].No > boardItem.IntData then
925                                 boardItem.Items[index].AgeSage := gasAge
926                         else if boardItem.Items[index].AllResCount < inCount then
927                                 boardItem.Items[index].AgeSage := gasSage
928                         else
929                                 boardItem.Items[index].AgeSage := gasNone;
930
931                         boardItem.Items[index].No                                               := boardItem.IntData;
932                         boardItem.Items[index].AllResCount      := inCount;
933 //                              if not boardItem.Items[index].IsLogFile then
934 //                                      boardItem.Items[index].Count := inCountt;
935                         boardItem.ListData.Add( boardItem.Items[index] );
936                         boardItem.DeleteList( index );
937                 end;
938         end;
939 begin
940         Board.ListData := TList.Create;
941         Body := TStringList.Create;
942         try
943                 //\83_\83E\83\93\83\8d\81[\83h\93ú\8e\9e\90Ý\92è\81i\83\8d\81[\83J\83\8b\93ú\8e\9e\81j
944                 Board.RoundDate := Now;
945                 //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
946                 Board.LastModified := LastModified;
947
948                 if Board.IsBoardPlugInAvailable then begin
949                         // \90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
950                         // \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Á
951                         // \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¬
952                         Board.IntData := 0;
953                         Board.BoardPlugIn.EnumThread( DWORD( Board ), @MakeThreadCallBack );
954
955                         // \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Á
956                         for i := 0 to Board.Count - 1 do begin
957                                 if Board.Items[i].IsLogFile then begin
958                                         Board.IntData := Board.IntData + 1;
959                                         Board.Items[i].No                                               := Board.IntData;
960                                         Board.Items[i].AllResCount      := Board.Items[i].Count;
961                                         Board.Items[i].NewResCount      := 0;
962                                         Board.Items[i].AgeSage                  := gasNone;
963                                         Board.ListData.Add( Board.Items[i] );
964                                 end;
965                         end;
966
967                         // \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
968                         for i := Board.Count - 1 downto 0 do
969                                 Board.DeleteList( i );
970
971                         // \90V\82µ\82¢\83\8a\83X\83g\82ð\83{\81[\83h\83I\83u\83W\83F\83N\83g\82É\92Ç\89Á
972                         for i := 0 to Board.ListData.Count - 1 do
973                                 Board.Add( TThreadItem(Board.ListData[i]) );
974                 end else begin
975                         //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
976                         //\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Á
977                         //\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¬
978                         Body.Text := Content;
979                         NumCount := 0;
980                         for i := 0 to Body.Count - 1 do begin
981                                 //if i = 0 then Continue;       //\82P\8ds\96Ú\82Í\83X\83e\81[\83^\83X\8ds\82Ì\82½\82ß\8f\88\97\9d\82È\82µ
982
983                                 Rec := GikoSys.DivideSubject(Body[i]);
984                                 Rec.FFileName := Trim(Rec.FFileName);
985                                 if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
986                                 Inc(NumCount);
987                                 index := Board.GetIndex(Rec.FFileName);
988                                 if index = -1 then begin
989                                         //\90V\82µ\82¢\83X\83\8c\83b\83h
990                                         NewItem := TThreadItem.Create(
991                 nil, GikoSys.Get2chBoard2ThreadURL( Board, ChangeFileExt( Rec.FFileName, '' ) ) );
992                                         NewItem.FileName := Rec.FFileName;
993                                         NewItem.Title := Rec.FTitle;
994         //                              NewItem.Count := Rec.FCount;
995                                         NewItem.AllResCount := Rec.FCount;
996                                         NewItem.ParentBoard := Board;
997                                         NewItem.No := NumCount;
998                                         NewItem.RoundDate := ZERO_DATE;
999                                         NewItem.LastModified := ZERO_DATE;
1000                                         NewItem.AgeSage := gasNew;
1001                                         Board.ListData.Add(NewItem);
1002                                 end else begin
1003                                         //Board.Items[index].Count := Count;
1004                                         //Board.Items[index].Count := Rec.FCount;
1005                                         if Board.Items[index].No > NumCount then
1006                                                 Board.Items[index].AgeSage := gasAge
1007                                         else if Board.Items[index].AllResCount < Rec.FCount then
1008                                                 Board.Items[index].AgeSage := gasSage
1009                                         else
1010                                                 Board.Items[index].AgeSage := gasNone;
1011
1012
1013                                         Board.Items[index].No := NumCount;
1014                                         Board.Items[index].AllResCount := Rec.FCount;
1015         //                              if not Board.Items[index].IsLogFile then
1016         //                                      Board.Items[index].Count := Rec.FCount;
1017                                         Board.ListData.Add(Board.Items[index]);
1018                                         Board.DeleteList(index);
1019                                 end;
1020                         end;
1021
1022                         //\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Á
1023                         for i := 0 to Board.Count - 1 do begin
1024                                 if Board.Items[i].IsLogFile then begin
1025                                         inc(NumCount);
1026                                         Board.Items[i].No := NumCount;
1027                                         Board.Items[i].AllResCount := Board.Items[i].Count;
1028                                         Board.Items[i].NewResCount := 0;
1029                                         Board.Items[i].AgeSage := gasNone;
1030                                         Board.ListData.Add(Board.Items[i]);
1031                                 end;
1032                         end;
1033
1034                         //\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
1035                         for i := Board.Count - 1 downto 0 do
1036                                 Board.DeleteList(i);
1037
1038                         //\90V\82µ\82¢\83\8a\83X\83g\82ð\83{\81[\83h\83I\83u\83W\83F\83N\83g\82É\92Ç\89Á
1039                         for i := 0 to Board.ListData.Count - 1 do
1040                                 Board.Add(TThreadItem(Board.ListData[i]));
1041
1042                         //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
1043         //              GikoSys.ForceDirectoriesEx(GikoSys.GetLogDir + Board.BBSID);
1044         //              Body.SaveToFile(GikoSys.GetSubjectFileName(Board.BBSID));
1045                         GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
1046                         Body.SaveToFile(Board.GetSubjectFileName);
1047                 end;
1048         finally
1049                 Body.Free;
1050                 Board.ListData.Free;
1051         end;
1052 end;
1053
1054 {procedure TDownloadItem.SaveListFile;
1055 var
1056         i: Integer;
1057         index: Integer;
1058         NewItem: TThreadItem;
1059         NewList: TList;
1060 //      SaveCount: Integer;
1061         NumCount: Integer;
1062         Body: TStringList;
1063         Rec: TSubjectRec;
1064 begin
1065         NewList := TList.Create;
1066         Body := TStringList.Create;
1067         try
1068                 //\8f\84\89ñ\93ú\8e\9e\90Ý\92è
1069                 Board.RoundDate := Now;
1070                 //\83T\81[\83o\8fã\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\90Ý\92è
1071                 Board.LastModified := LastModified;
1072
1073                 //\83\8a\83X\83g\95Û\91\8c\8f\90\94\8eæ\93¾
1074                 //SaveCount := MaxInt;
1075
1076                 //\8cÃ\82¢\83\8a\83X\83g\82©\82ç\83\8d\83O\96³\82µ\83A\83C\83e\83\80\82ð\8dí\8f\9c
1077                 for i := Board.Count - 1 downto 0 do
1078                         if not Board.Items[i].IsLogFile then
1079                                 Board.Delete(i);
1080
1081                 //\90V\82µ\82¢\83\8a\83X\83g\82ð\8dì\90¬\82·\82é
1082                 //\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Á
1083                 //\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¬
1084                 Body.Text := Content;
1085 //              Loop := Min(Body.Count, SaveCount);
1086                 NumCount := 0;
1087 //              for i := 0 to Loop - 1 do begin
1088                 for i := 0 to Body.Count - 1 do begin
1089                         if i = 0 then Continue; //\82P\8ds\96Ú\82Í\83X\83e\81[\83^\83X\8ds\82Ì\82½\82ß\8f\88\97\9d\82È\82µ
1090
1091                         Rec := GikoSys.DivideSubject(Body[i]);
1092                         if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
1093                         Inc(NumCount);
1094                         index := Board.GetIndex(Rec.FFileName);
1095                         if index = -1 then begin
1096                                 NewItem := TThreadItem.Create;
1097                                 NewItem.FileName := Rec.FFileName;
1098                                 NewItem.Title := Rec.FTitle;
1099                                 NewItem.Count := Rec.FCount;
1100                                 NewItem.ParentBoard := Board;
1101                                 NewItem.No := NumCount;
1102                                 NewItem.RoundDate := ZERO_DATE;
1103                                 NewItem.LastModified := ZERO_DATE;
1104                                 NewList.Add(NewItem);
1105                         end else begin
1106                                 //Board.Items[index].Count := Count;
1107                                 Board.Items[index].No := NumCount;
1108                                 NewList.Add(Board.Items[index]);
1109                                 Board.DeleteList(index);
1110                         end;
1111                 end;
1112
1113                 //\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Á
1114                 for i := 0 to Board.Count - 1 do begin
1115                         inc(NumCount);
1116                         Board.Items[i].No := NumCount;
1117                         NewList.Add(Board.Items[i]);
1118                 end;
1119
1120                 //\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
1121                 for i := Board.Count - 1 downto 0 do
1122                         Board.DeleteList(i);
1123
1124                 //\90V\82µ\82¢\83\8a\83X\83g\82ð\83{\81[\83h\83I\83u\83W\83F\83N\83g\82É\92Ç\89Á
1125                 for i := 0 to NewList.Count - 1 do
1126                         Board.Add(TThreadItem(NewList[i]));
1127
1128                 //\83\8a\83X\83g(subject.txt)\82ð\95Û\91
1129 //              GikoSys.ForceDirectoriesEx(GikoSys.GetLogDir + Board.BBSID);
1130 //              Body.SaveToFile(GikoSys.GetSubjectFileName(Board.BBSID));
1131                 GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
1132                 Body.SaveToFile(Board.GetSubjectFileName);
1133         finally
1134                 Body.Free;
1135                 NewList.Free;
1136         end;
1137 end;
1138 }
1139 procedure TDownloadItem.SaveItemFile;
1140 var
1141         Body: TStringList;
1142         Cnt: Integer;
1143         OldCnt: Integer;
1144         FileName: string;
1145         ini: TMemIniFile;
1146         Res: TResRec;
1147         NewRes: Integer;
1148 begin
1149         FileName := ThreadItem.GetThreadFileName;
1150
1151         if not ThreadItem.IsBoardPlugInAvailable then begin
1152                 if Trim(Content) = '' then
1153                         Exit;
1154                 GikoSys.ForceDirectoriesEx(ExtractFilePath(FileName));
1155
1156         //      Cnt := 0;
1157                 Body := TStringList.Create;
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                                 Body.LoadFromFile(FileName);
1166                                 OldCnt := Body.Count;
1167                                 Body.Text := Body.Text + Content;
1168                                 Body.SaveToFile(FileName);
1169                                 NewRes := Body.Count - OldCnt;
1170                                 Cnt := Body.Count;
1171                         end else begin
1172                                 Body.Text := Content;
1173         //                      if Body.Count > 0 then
1174         //                              Body.Delete(0);
1175                                 Body.SaveToFile(FileName);
1176
1177                                 if ThreadItem.Title = '' then begin
1178                                         Res := GikoSys.DivideStrLine(Body[0]);
1179                                         ThreadItem.Title := Res.FTitle;
1180                                 end;
1181                                 ThreadItem.Size := 0;
1182                                 //ThreadItem.Count := 0;
1183                                 ThreadItem.AllResCount := 0;
1184                                 ThreadItem.NewResCount := 0;
1185                                 OldCnt := 0;
1186                                 NewRes := Body.Count;
1187                                 Cnt := Body.Count;
1188                         end;
1189                         Cnt := Body.Count;
1190                 finally
1191                         Body.Free;
1192                 end;
1193                 ThreadItem.Size := ThreadItem.Size + ContentLength;
1194                 ThreadItem.LastModified := LastModified;
1195                 ThreadItem.Count := Cnt;
1196                 ThreadItem.AllResCount := Cnt;
1197                 ThreadItem.NewResCount := NewRes;
1198                 ThreadItem.NewReceive := OldCnt + 1;
1199         end;
1200
1201         ThreadItem.IsLogFile := True;
1202         ThreadItem.RoundDate := Now;
1203         ThreadItem.UnRead := True;
1204         ThreadItem.ParentBoard.UnRead := ThreadItem.ParentBoard.UnRead + 1;
1205 //      if ThreadItem.RoundNo = 6 then
1206 //              ThreadItem.RoundNo := 0;
1207
1208         //\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
1209         //\90³\8fí\8fI\97¹\8e\9e\82É\82Í\8dí\8f\9c
1210         //\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
1211         ini := TMemIniFile.Create(ChangeFileExt(FileName, '.tmp'));
1212         try
1213                 ini.WriteDateTime('Setting', 'RoundDate', ThreadItem.RoundDate);
1214                 ini.WriteDateTime('Setting', 'LastModified', ThreadItem.LastModified);
1215                 ini.WriteInteger('Setting', 'Size', ThreadItem.Size);
1216                 ini.WriteInteger('Setting', 'Count', ThreadItem.Count);
1217                 ini.WriteInteger('Setting', 'AllResCount', ThreadItem.AllResCount);
1218                 ini.WriteInteger('Setting', 'NewResCount', ThreadItem.NewResCount);
1219                 ini.WriteInteger('Setting', 'NewReceive', ThreadItem.NewReceive);
1220 //              ini.WriteInteger('Setting', 'RoundNo', ThreadItem.RoundNo);
1221                 ini.WriteBool('Setting', 'Round', ThreadItem.Round);
1222                 ini.WriteBool('Setting', 'UnRead', ThreadItem.UnRead);
1223                 ini.UpdateFile;
1224         finally
1225                 ini.Free;
1226         end;
1227 end;
1228
1229 end.