OSDN Git Service

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