OSDN Git Service

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