OSDN Git Service

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