6 SysUtils, Classes, ComCtrls, Controls, Forms, IdHTTP,
7 {HTTPApp,} YofUtils, IdGlobal, IdException, IdComponent, IniFiles, {DateUtils,}
8 GikoSystem, BoardGroup, MonaUtils;
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);
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;
24 FStatus: TGikoCgiStatus;
30 TDownloadThread = class(TThread)
37 FIcon: TGikoMessageIcon;
39 FOnWork: TGikoWorkEvent;
40 FOnWorkBegin: TGikoWorkBeginEvent;
41 FOnWorkEnd: TGikoWorkEndEvent;
42 FOnDownloadEnd: TDownloadEndEvent;
43 FOnDownloadMsg: TDownloadMsgEvent;
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 DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
53 function DeleteStatusLine(Content: string): string;
55 procedure Execute; override;
57 property Item: TDownloadItem read FItem write FItem;
58 property Number: Integer read FNumber write FNumber;
59 constructor Create(CreateSuspended: Boolean);
60 destructor Destroy; override;
62 property OnWork: TGikoWorkEvent read FOnWork write FOnWork;
63 property OnWorkBegin: TGikoWorkBeginEvent read FOnWorkBegin write FOnWorkBegin;
64 property OnWorkEnd: TGikoWorkEndEvent read FOnWorkEnd write FOnWorkEnd;
65 property OnDownloadEnd: TDownloadEndEvent read FOnDownloadEnd write FOnDownloadEnd;
66 property OnDownloadMsg: TDownloadMsgEvent read FOnDownloadMsg write FOnDownloadMsg;
69 TDownloadItem = class(TObject)
71 FDownType: TGikoDownloadType;
73 FThreadItem: TThreadItem;
75 FContentLength: Integer;
76 FLastModified: TDateTime;
78 FResponseCode: Smallint;
79 FState: TGikoDownloadState;
82 procedure SaveListFile;
83 procedure SaveItemFile;
85 property DownType: TGikoDownloadType read FDownType write FDownType;
86 property Board: TBoard read FBoard write FBoard;
87 property ThreadItem: TThreadItem read FThreadItem write FThreadItem;
89 property ContentLength: Integer read FContentLength write FContentLength;
90 property LastModified: TDateTime read FLastModified write FLastModified;
91 property Content: string read FContent write FContent;
92 property ResponseCode: Smallint read FResponseCode write FResponseCode;
93 property State: TGikoDownloadState read FState write FState;
94 property ErrText: string read FErrText write FErrText;
99 constructor TDownloadThread.Create(CreateSuspended: Boolean);
101 inherited Create(CreateSuspended);
102 FIndy := TIdHttp.Create(nil);
104 FIndy.OnWorkBegin := WorkBegin;
105 FIndy.OnWorkEnd := WorkEnd;
106 FIndy.OnWork := Work;
109 destructor TDownloadThread.Destroy;
115 function RFC1123_Date(aDate : TDateTime) : String;
117 StrWeekDay : String = 'MonTueWedThuFriSatSun';
118 StrMonth : String = 'JanFebMarAprMayJunJulAugSepOctNovDec';
120 Year, Month, Day : Word;
121 Hour, Min, Sec, MSec : Word;
124 DecodeDate(aDate, Year, Month, Day);
125 DecodeTime(aDate, Hour, Min, Sec, MSec);
126 DayOfWeek := ((Trunc(aDate) - 2) mod 7);
127 Result := Copy(StrWeekDay, 1 + DayOfWeek * 3, 3) + ', ' +
128 Format('%2.2d %s %4.4d %2.2d:%2.2d:%2.2d',
129 [Day, Copy(StrMonth, 1 + 3 * (Month - 1), 3),
130 Year, Hour, Min, Sec]);
133 procedure TDownloadThread.Execute;
135 ResStream: TMemoryStream;
138 CgiStatus: TCgiStatus;
144 DownloadResult: Boolean;
147 while not Terminated do begin
149 FIndy.Request.CustomHeaders.Clear;
150 FIndy.Response.Clear;
152 FIndy.Request.UserAgent := GikoSys.GetUserAgent;
153 FIndy.RecvBufferSize := Gikosys.Setting.RecvBufferSize;
154 FIndy.ProxyParams.BasicAuthentication := False;
156 Writeln('------------------------------------------------------------');
158 //FIndy.AllowCookies := False;
159 if GikoSys.Setting.ReadProxy then begin
160 if GikoSys.Setting.ProxyProtocol then
161 FIndy.ProtocolVersion := pv1_1
163 FIndy.ProtocolVersion := pv1_0;
164 FIndy.ProxyParams.ProxyServer := GikoSys.Setting.ReadProxyAddress;
165 FIndy.ProxyParams.ProxyPort := GikoSys.Setting.ReadProxyPort;
166 FIndy.ProxyParams.ProxyUsername := GikoSys.Setting.ReadProxyUserID;
167 FIndy.ProxyParams.ProxyPassword := GikoSys.Setting.ReadProxyPassword;
168 if GikoSys.Setting.ReadProxyUserID <> '' then
169 FIndy.ProxyParams.BasicAuthentication := True;
171 Writeln('
\83v
\83\8d\83L
\83V
\90Ý
\92è
\82 \82è');
172 Writeln('
\83z
\83X
\83g: ' + GikoSys.Setting.ReadProxyAddress);
173 Writeln('
\83|
\81[
\83g: ' + IntToStr(GikoSys.Setting.ReadProxyPort));
176 if GikoSys.Setting.Protocol then
177 FIndy.ProtocolVersion := pv1_1
179 FIndy.ProtocolVersion := pv1_0;
180 FIndy.ProxyParams.ProxyServer := '';
181 FIndy.ProxyParams.ProxyPort := 80;
182 FIndy.ProxyParams.ProxyUsername := '';
183 FIndy.ProxyParams.ProxyPassword := '';
185 Writeln('
\83v
\83\8d\83L
\83V
\90Ý
\92è
\82È
\82µ');
189 FIndy.Request.ContentRangeStart := 0;
190 FIndy.Request.LastModified := ZERO_DATE;
191 ResStream := TMemoryStream.Create;
194 //********************
195 //DAT or Subject
\8eæ
\93¾
196 //********************
197 Item.ResponseCode := 0;
201 if Item.DownType = gdtBoard then begin
203 Writeln('Subject
\8eæ
\93¾');
204 Writeln('URL: ' + Item.Board.GetReadCgiURL);
205 Writeln('Modified: ' + FloatToStr(Item.Board.LastModified));
207 URL := Item.Board.GetReadCgiURL;
208 Modified := Item.Board.LastModified;
209 end else if Item.DownType = gdtThread then begin
211 Writeln('DAT
\8eæ
\93¾');
212 Writeln('URL: ' + Item.ThreadItem.GetDatURL);
213 Writeln('Modified: ' + FloatToStr(Item.ThreadItem.LastModified));
215 URL := Item.ThreadItem.GetDatURL;
216 Modified := Item.ThreadItem.LastModified;
217 if Item.ThreadItem.Size > 0 then begin
219 Writeln('RangeStart: ' + IntToStr(Item.ThreadItem.Size));
221 //
\82 \82Ú
\81[
\82ñ
\83`
\83F
\83b
\83N
\82Ì
\82½
\82ß
\82P
\83o
\83C
\83g
\91O
\82©
\82ç
\8eæ
\93¾
222 RangeStart := Item.ThreadItem.Size;
227 DownloadResult := DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen);
229 Writeln('ResponseCode: ' + IntToStr(FIndy.ResponseCode));
231 if Item.DownType = gdtThread then begin
232 if Item.ResponseCode = 416 then begin
234 DownloadResult := True;
235 end else if DownloadResult and (AdjustLen = -1) and (Item.Content[1] <> #10) then
239 if Trim(FIndy.Response.RawHeaders.Values['Date']) <> '' then begin
240 if Item.DownType = gdtBoard then
241 Item.Board.LastGetTime := MonaUtils.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date'])
243 Item.ThreadItem.ParentBoard.LastGetTime := MonaUtils.DateStrToDateTime(FIndy.Response.RawHeaders.Values['Date']);
246 if DownloadResult then begin
248 Writeln('Date:' + FIndy.Response.RawHeaders.Values['Date']);
252 Writeln('
\82 \82Ú
\81[
\82ñ
\8c\9f\8fo');
254 ATitle := Item.ThreadItem.Title;
256 ATitle := '
\81i
\96¼
\8fÌ
\95s
\96¾
\81j';
257 //
\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 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 if FileExists(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG')) = true then
263 DeleteFile(ChangeFileExt(Item.FThreadItem.GetThreadFileName,'.NG'));
264 if Assigned(OnDownloadMsg) then
265 Synchronize(FireDownloadMsg);
266 if not DatDownload(Item.DownType, URL, ZERO_DATE, RangeStart, AdjustLen) then
267 Item.State := gdsError;
269 Writeln('
\82 \82Ú
\81[
\82ñ
\8dÄ
\8eæ
\93¾
\8cã');
270 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
272 end else if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] = #10) then begin
273 //
\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
274 Item.Content := Copy(Item.Content, 2, Length(Item.Content));
277 Item.State := gdsError;
278 if (Item.DownType = gdtBoard) and (Item.ResponseCode = 302) then begin
279 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 if Assigned(OnDownloadMsg) then
282 Synchronize(FireDownloadMsg);
286 //********************
288 //********************
289 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
291 Writeln('dat.gz
\8eæ
\93¾');
293 ATitle := Item.ThreadItem.Title;
295 ATitle := '
\81i
\96¼
\8fÌ
\95s
\96¾
\81j';
296 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 if Assigned(OnDownloadMsg) then
299 Synchronize(FireDownloadMsg);
300 URL := Item.ThreadItem.GetDatgzURL;
301 Modified := Item.ThreadItem.LastModified;
304 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
305 Item.State := gdsError;
307 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
311 //********************
313 //********************
315 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
316 ATitle := Item.ThreadItem.Title;
318 ATitle := '
\81i
\96¼
\8fÌ
\95s
\96¾
\81j';
319 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 if Assigned(OnDownloadMsg) then
322 Synchronize(FireDownloadMsg);
323 URL := Item.ThreadItem.GetOldDatgzURL;
324 Modified := Item.ThreadItem.LastModified;
327 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
328 Item.State := gdsError;
332 //********************
333 //offlaw.cgi
\82Å
\8eæ
\93¾
334 //********************
336 Synchronize(GetSessionID);
337 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID <> '') then begin
339 Writeln('offlaw.cgi
\82Å
\8eæ
\93¾');
341 ATitle := Item.ThreadItem.Title;
343 ATitle := '
\81i
\96¼
\8fÌ
\95s
\96¾
\81j';
344 FMsg := '
\81\9adat.gz
\82ª
\91¶
\8dÝ
\82µ
\82È
\82¢
\82½
\82ßofflaw.cgi
\82ð
\97\98\97p
\82µ
\82Ü
\82· - [' + ATitle + ']';
346 if Assigned(OnDownloadMsg) then
347 Synchronize(FireDownloadMsg);
348 URL := Item.ThreadItem.GetOfflawCgiURL(FSessionID);
349 Modified := Item.ThreadItem.LastModified;
352 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then begin
354 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
356 Item.State := gdsError;
358 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) then begin
359 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 if Assigned(OnDownloadMsg) then
362 Synchronize(FireDownloadMsg);
366 CgiStatus := ParseCgiStatus(Item.Content);
368 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
370 case CgiStatus.FStatus of
373 Writeln('CGIStatus: OK');
375 Item.ResponseCode := 200;
376 Item.Content := DeleteStatusLine(Item.Content);
377 Item.ContentLength := CgiStatus.FSize;
380 //
\8d¡
\82Í
\82 \82è
\82¦
\82È
\82¢
382 Writeln('CGIStatus: 206');
384 Item.ResponseCode := 206;
385 Item.Content := DeleteStatusLine(Item.Content);
386 Item.ContentLength := CgiStatus.FSize;
390 Writeln('CGIStatus: 404(ERROR)');
392 Item.ResponseCode := 404;
393 Item.State := gdsError;
394 Item.ErrText := CgiStatus.FErrText;
397 if (Item.ResponseCode = 404) and (AnsiPos('
\89ß
\8b\8e\83\8d\83O
\91q
\8cÉ
\82Å
\94
\8c©', Item.ErrText) <> 0) then begin
399 Writeln('
\89ß
\8b\8e\83\8d\83O
\8eæ
\93¾');
401 ATitle := Item.ThreadItem.Title;
403 ATitle := '
\81i
\96¼
\8fÌ
\95s
\96¾
\81j';
404 FMsg := '
\81\9a\89ß
\8b\8e\83\8d\83O
\91q
\8cÉ
\82Å
\94
\8c© - [' + ATitle + ']';
406 if Assigned(OnDownloadMsg) then
407 Synchronize(FireDownloadMsg);
408 Idx := Pos(' ', Item.ErrText);
409 if Idx <> 0 then begin
410 URL := Copy(Item.ErrText, Idx + 1, Length(Item.ErrText));
411 if Pos('../', URL) = 1 then
412 URL := Copy(URL, 4, Length(URL));
413 URL := GikoSys.UrlToServer(Item.ThreadItem.ParentBoard.URL) + URL;
414 Modified := Item.ThreadItem.LastModified;
417 if not DatDownload(Item.DownType, URL, Modified, RangeStart, AdjustLen) then
418 Item.State := gdsError;
420 Writeln('ResponseCode: ' + IntToStr(Item.ResponseCode));
426 if (Item.DownType = gdtThread) and (Item.ResponseCode = 302) and (FSessionID = '') then begin
428 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 ATitle := Item.ThreadItem.Title;
432 ATitle := '
\81i
\96¼
\8fÌ
\95s
\96¾
\81j';
433 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 if Assigned(OnDownloadMsg) then
436 Synchronize(FireDownloadMsg);
440 case Item.ResponseCode of
441 200: Item.State := gdsComplete;
442 206: Item.State := gdsDiffComplete;
443 304: Item.State := gdsNotModify;
445 Item.State := gdsError;
448 //
\96³
\82¢
\82Æ
\8ev
\82¤
\82¯
\82Ç
\81B
\81B
\81B
449 if (Item.ResponseCode in [200, 206]) and (Item.Content = '') then
450 Item.State := gdsError;
451 Item.LastModified := FIndy.Response.LastModified;
452 //
\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é
453 Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
456 FIndy.Get(URL, ResStream);
457 Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
458 if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] <> #10) then begin
459 //
\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¾
460 //
\82±
\82±
\82Å
\83\81\83b
\83Z
\81[
\83W
\95\
\8e¦
\83C
\83x
\83\93\83g
462 FMsg := '
\81u
\82 \82Ú
\81[
\82ñ
\81v
\82ð
\8c\9f\8fo
\82µ
\82½
\82Ì
\82Å
\8dÄ
\8eæ
\93¾
\82ð
\8ds
\82¢
\82Ü
\82·';
463 if Assigned(OnDownloadMsg) then
464 Synchronize(FireDownloadMsg);
465 FIndy.Request.ContentRangeStart := 0;
466 FIndy.Request.ContentRangeEnd := 0;
469 FIndy.Get(URL, ResStream);
470 Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
471 end else if (Item.DownType = gdtThread) and (AdjustLen = -1) and (Item.Content[1] = #10) then begin
472 //
\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
473 Item.Content := Copy(Item.Content, 2, Length(Item.Content));
476 Item.State := gdsError;
478 Item.ResponseCode := FIndy.ResponseCode;
483 FIndy.Get(URL, ResStream);
484 Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
486 Item.State := gdsError;
489 CgiStatus := ParseCgiStatus(Item.Content);
490 if CgiStatus.FStatus = gcsOK then begin
491 if CgiStatus.FSize = 0 then
492 Item.State := gdsNotModify
493 else if Item.DownType = gdtBoard then
494 Item.State := gdsComplete
496 Item.State := gdsDiffComplete;
497 end else if CgiStatus.FStatus = gcsINCR then begin
498 Item.State := gdsComplete;
499 end else if CgiStatus.FStatus = gcsERR then begin
500 Item.State := gdsError;
501 Item.ErrText := CgiStatus.FErrText;
503 Item.ContentLength := CgiStatus.FSize;
506 Item.State := gdsError;
508 //Item.ResponseCode := FIndy.ResponseCode;
510 Item.State := gdsAbort;
512 if Assigned(OnDownloadEnd) then
513 Synchronize(FireDownloadEnd);
516 if Terminated then Break;
521 function TDownloadThread.DatDownload(ItemType: TGikoDownloadType; URL: string; Modified: TDateTime; RangeStart: Integer; AdjustLen: Integer): Boolean;
523 ResponseCode: Integer;
524 ResStream: TMemoryStream;
527 if (ItemType = gdtThread) and (RangeStart > 0) then begin
528 // if (ItemType = gdtThread) and (Item.ThreadItem.Size > 0) then begin
529 // FIndy.Request.ContentRangeStart := Item.ThreadItem.Size + AdjustLen;
530 FIndy.Request.ContentRangeStart := RangeStart + AdjustLen;
531 FIndy.Request.ContentRangeEnd := 0;
533 FIndy.Request.ContentRangeStart := 0;
534 FIndy.Request.ContentRangeEnd := 0;
537 FIndy.Request.CustomHeaders.Clear;
538 FIndy.Request.CacheControl := 'no-cache';
539 FIndy.Request.CustomHeaders.Add('Pragma: no-cache');
540 if (Modified <> 0) and (Modified <> ZERO_DATE) then begin
541 FIndy.Request.LastModified := modified - OffsetFromUTC;
542 //FIndy.Request.CustomHeaders.Add('If-Modified-Since: ' + RFC1123_Date(modified - OffsetFromUTC) + ' GMT');
544 // FIndy.Request.AcceptEncoding := 'gzip';
545 if RangeStart = 0 then
546 FIndy.Request.AcceptEncoding := 'gzip'
548 FIndy.Request.AcceptEncoding := '';
549 ResStream := TMemoryStream.Create;
554 Writeln('URL: ' + URL);
556 FIndy.Get(URL, ResStream);
557 Item.Content := GikoSys.GzipDecompress(ResStream, FIndy.Response.ContentEncoding);
558 Item.LastModified := FIndy.Response.LastModified;
559 //
\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é
560 // Item.ContentLength := FIndy.Response.ContentLength + AdjustLen;
561 Item.ContentLength := Length(Item.Content) + AdjustLen;
562 //
\96³
\82¢
\82Æ
\8ev
\82¤
\82¯
\82Ç
\81B
\81B
\81B
563 // if (FIndy.ResponseCode in [200, 206]) and (Item.Content = '') then
565 if Item.Content = '' then
570 Writeln('
\8eæ
\93¾
\82Å
\97á
\8aO
\82È
\82µ');
572 ResponseCode := FIndy.ResponseCode;
574 on E: EIdSocketError do begin
576 Item.LastModified := ZERO_DATE;
577 Item.ContentLength := 0;
578 Item.ErrText := E.Message;
581 Screen.Cursor := crDefault;
583 on E: EIdConnectException do begin
585 Item.LastModified := ZERO_DATE;
586 Item.ContentLength := 0;
587 Item.ErrText := E.Message;
590 Screen.Cursor := crDefault;
592 on E: Exception do begin
594 Writeln('
\8eæ
\93¾
\82Å
\97á
\8aO
\82 \82è');
595 Writeln('E.Message: ' + E.Message);
598 Item.LastModified := ZERO_DATE;
599 Item.ContentLength := 0;
600 Item.ErrText := E.Message;
601 ResponseCode := FIndy.ResponseCode;
603 Screen.Cursor := crDefault;
607 if (Item.ContentLength = 0) and (ResponseCode = 206) then
608 Item.ResponseCode := 304
610 Item.ResponseCode := ResponseCode;
615 procedure TDownloadThread.FireDownloadEnd;
617 OnDownloadEnd(self, Item);
620 procedure TDownloadThread.FireDownloadMsg;
622 OnDownloadMsg(Self, Item, FMsg, FIcon);
625 procedure TDownloadThread.GetSessionID;
627 FSessionID := GikoSys.Dolib.SessionID;
630 procedure TDownloadThread.Abort;
633 FIndy.DisconnectSocket;
636 procedure TDownloadThread.WorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer);
638 if Assigned(OnWorkBegin) then
639 OnWorkBegin(Sender, AWorkMode, AWorkCountMax, FNumber);
642 procedure TDownloadThread.WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
644 if Assigned(OnWorkEnd) then
645 OnWorkEnd(Sender, AWorkMode, FNumber);
648 procedure TDownloadThread.Work(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer);
650 if Assigned(OnWork) then
651 OnWork(Sender, AWorkMode, AWorkCount, FNumber);
654 function TDownloadThread.ParseCgiStatus(Content: string): TCgiStatus;
663 // [+OK]
\82Ì
\8fê
\8d\87\82Í
\8d·
\95ª
664 // [-INCR] (Incorrect)
\82Ì
\8fê
\8d\87\82Í
\82·
\82×
\82Ä
\82Ì
\83f
\81[
\83^
665 // [-ERR (
\83e
\83L
\83X
\83g)]
\82Ì
\8fê
\8d\87\82Í
\82È
\82ñ
\82©
\83G
\83\89\81[
666 //
\97á
\81F+OK 23094/512K
668 // -ERR
\82»
\82ñ
\82È
\94Â
\82È
\82¢
\82Å
\82·
669 Idx := AnsiPos(#10, Content);
670 StatusLine := Copy(Content, 0, Idx);
672 Idx := AnsiPos(' ', Content);
673 Status := Copy(StatusLine, 0, Idx - 1);
674 Line := Copy(StatusLine, Idx + 1, Length(StatusLine));
676 // Idx := AnsiPos('/', Line);
677 if Trim(Status) = '-ERR' then
680 Size := Copy(Line, 0, Idx - 1);
682 if Trim(Status) = '+OK' then
683 Result.FStatus := gcsOK
684 else if Trim(Status) = '-INCR' then
685 Result.FStatus := gcsINCR
686 else if Trim(Status) = '-ERR' then begin
687 Result.FStatus := gcsERR;
688 Result.FErrText := Msg;
695 Result.FStatus := gcsERR;
696 Result.FErrText := '
\83G
\83\89\81[
\82È
\82ñ
\82¾
\82¯
\82Ç
\81A
\82æ
\82
\95ª
\82©
\82ç
\82È
\82¢
\83G
\83\89\81[';
701 if GikoSys.IsNumeric(Size) then
702 Result.FSize := StrToInt(Size)
705 Result.FStatus := gcsERR;
706 Result.FErrText := '
\83X
\83e
\81[
\83^
\83X
\89ð
\90Í
\8e¸
\94s[' + StatusLine + ']';
710 //
\8eè
\94²
\82«
\82È
\8f\88\97\9d\82Å1
\8ds
\96Ú
\82ð
\8fÁ
\82·
711 function TDownloadThread.DeleteStatusLine(Content: string): string;
715 SList := TStringList.Create;
717 SList.Text := Content;
718 if SList.Count > 1 then
720 Result := SList.Text;
726 procedure TDownloadItem.SaveListFile;
730 NewItem: TThreadItem;
732 // SaveCount: Integer;
737 NewList := TList.Create;
738 Body := TStringList.Create;
740 //
\83_
\83E
\83\93\83\8d\81[
\83h
\93ú
\8e\9e\90Ý
\92è
\81i
\83\8d\81[
\83J
\83\8b\93ú
\8e\9e\81j
741 Board.RoundDate := Now;
742 //
\83T
\81[
\83o
\8fã
\83t
\83@
\83C
\83\8b\82Ì
\8dX
\90V
\8e\9e\8d\8f\90Ý
\92è
743 Board.LastModified := LastModified;
745 //
\90V
\82µ
\82¢
\83\8a\83X
\83g
\82ð
\8dì
\90¬
\82·
\82é
746 //
\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Á
747 //
\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¬
748 Body.Text := Content;
750 for i := 0 to Body.Count - 1 do begin
751 //if i = 0 then Continue; //
\82P
\8ds
\96Ú
\82Í
\83X
\83e
\81[
\83^
\83X
\8ds
\82Ì
\82½
\82ß
\8f\88\97\9d\82È
\82µ
753 Rec := GikoSys.DivideSubject(Body[i]);
754 Rec.FFileName := Trim(Rec.FFileName);
755 if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
757 index := Board.GetIndex(Rec.FFileName);
758 if index = -1 then begin
759 //
\90V
\82µ
\82¢
\83X
\83\8c\83b
\83h
760 NewItem := TThreadItem.Create;
761 NewItem.FileName := Rec.FFileName;
762 NewItem.Title := Rec.FTitle;
763 // NewItem.Count := Rec.FCount;
764 NewItem.AllResCount := Rec.FCount;
765 NewItem.ParentBoard := Board;
766 NewItem.No := NumCount;
767 NewItem.RoundDate := ZERO_DATE;
768 NewItem.LastModified := ZERO_DATE;
769 NewItem.AgeSage := gasNew;
770 NewList.Add(NewItem);
772 //Board.Items[index].Count := Count;
773 //Board.Items[index].Count := Rec.FCount;
774 if Board.Items[index].No > NumCount then
775 Board.Items[index].AgeSage := gasAge
776 else if Board.Items[index].AllResCount < Rec.FCount then
777 Board.Items[index].AgeSage := gasSage
779 Board.Items[index].AgeSage := gasNone;
782 Board.Items[index].No := NumCount;
783 Board.Items[index].AllResCount := Rec.FCount;
784 // if not Board.Items[index].IsLogFile then
785 // Board.Items[index].Count := Rec.FCount;
786 NewList.Add(Board.Items[index]);
787 Board.DeleteList(index);
791 //
\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Á
792 for i := 0 to Board.Count - 1 do begin
793 if Board.Items[i].IsLogFile then begin
795 Board.Items[i].No := NumCount;
796 Board.Items[i].AllResCount := Board.Items[i].Count;
797 Board.Items[i].NewResCount := 0;
798 Board.Items[i].AgeSage := gasNone;
799 NewList.Add(Board.Items[i]);
803 //
\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
804 for i := Board.Count - 1 downto 0 do
807 //
\90V
\82µ
\82¢
\83\8a\83X
\83g
\82ð
\83{
\81[
\83h
\83I
\83u
\83W
\83F
\83N
\83g
\82É
\92Ç
\89Á
808 for i := 0 to NewList.Count - 1 do
809 Board.Add(TThreadItem(NewList[i]));
811 //
\83\8a\83X
\83g(subject.txt)
\82ð
\95Û
\91¶
812 // GikoSys.ForceDirectoriesEx(GikoSys.GetLogDir + Board.BBSID);
813 // Body.SaveToFile(GikoSys.GetSubjectFileName(Board.BBSID));
814 GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
815 Body.SaveToFile(Board.GetSubjectFileName);
822 {procedure TDownloadItem.SaveListFile;
826 NewItem: TThreadItem;
828 // SaveCount: Integer;
833 NewList := TList.Create;
834 Body := TStringList.Create;
836 //
\8f\84\89ñ
\93ú
\8e\9e\90Ý
\92è
837 Board.RoundDate := Now;
838 //
\83T
\81[
\83o
\8fã
\83t
\83@
\83C
\83\8b\82Ì
\8dX
\90V
\8e\9e\8d\8f\90Ý
\92è
839 Board.LastModified := LastModified;
841 //
\83\8a\83X
\83g
\95Û
\91¶
\8c\8f\90\94\8eæ
\93¾
842 //SaveCount := MaxInt;
844 //
\8cÃ
\82¢
\83\8a\83X
\83g
\82©
\82ç
\83\8d\83O
\96³
\82µ
\83A
\83C
\83e
\83\80\82ð
\8dí
\8f\9c
845 for i := Board.Count - 1 downto 0 do
846 if not Board.Items[i].IsLogFile then
849 //
\90V
\82µ
\82¢
\83\8a\83X
\83g
\82ð
\8dì
\90¬
\82·
\82é
850 //
\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Á
851 //
\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¬
852 Body.Text := Content;
853 // Loop := Min(Body.Count, SaveCount);
855 // for i := 0 to Loop - 1 do begin
856 for i := 0 to Body.Count - 1 do begin
857 if i = 0 then Continue; //
\82P
\8ds
\96Ú
\82Í
\83X
\83e
\81[
\83^
\83X
\8ds
\82Ì
\82½
\82ß
\8f\88\97\9d\82È
\82µ
859 Rec := GikoSys.DivideSubject(Body[i]);
860 if (Rec.FTitle = '') and (Rec.FCount = 0) then Continue;
862 index := Board.GetIndex(Rec.FFileName);
863 if index = -1 then begin
864 NewItem := TThreadItem.Create;
865 NewItem.FileName := Rec.FFileName;
866 NewItem.Title := Rec.FTitle;
867 NewItem.Count := Rec.FCount;
868 NewItem.ParentBoard := Board;
869 NewItem.No := NumCount;
870 NewItem.RoundDate := ZERO_DATE;
871 NewItem.LastModified := ZERO_DATE;
872 NewList.Add(NewItem);
874 //Board.Items[index].Count := Count;
875 Board.Items[index].No := NumCount;
876 NewList.Add(Board.Items[index]);
877 Board.DeleteList(index);
881 //
\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Á
882 for i := 0 to Board.Count - 1 do begin
884 Board.Items[i].No := NumCount;
885 NewList.Add(Board.Items[i]);
888 //
\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
889 for i := Board.Count - 1 downto 0 do
892 //
\90V
\82µ
\82¢
\83\8a\83X
\83g
\82ð
\83{
\81[
\83h
\83I
\83u
\83W
\83F
\83N
\83g
\82É
\92Ç
\89Á
893 for i := 0 to NewList.Count - 1 do
894 Board.Add(TThreadItem(NewList[i]));
896 //
\83\8a\83X
\83g(subject.txt)
\82ð
\95Û
\91¶
897 // GikoSys.ForceDirectoriesEx(GikoSys.GetLogDir + Board.BBSID);
898 // Body.SaveToFile(GikoSys.GetSubjectFileName(Board.BBSID));
899 GikoSys.ForceDirectoriesEx(ExtractFilePath(Board.GetSubjectFileName));
900 Body.SaveToFile(Board.GetSubjectFileName);
907 procedure TDownloadItem.SaveItemFile;
917 if Trim(Content) = '' then
919 FileName := ThreadItem.GetThreadFileName;
920 GikoSys.ForceDirectoriesEx(ExtractFilePath(FileName));
923 Body := TStringList.Create;
925 // if FileExists(FileName) and (ResponseCode = 206) then begin
926 if FileExists(FileName) and (State = gdsDiffComplete) then begin
927 // Body.Text := Content;
928 // if Body.Count > 0 then
930 // Content := Body.Text;
931 Body.LoadFromFile(FileName);
932 OldCnt := Body.Count;
933 Body.Text := Body.Text + Content;
934 Body.SaveToFile(FileName);
935 NewRes := Body.Count - OldCnt;
938 Body.Text := Content;
939 // if Body.Count > 0 then
941 Body.SaveToFile(FileName);
943 if ThreadItem.Title = '' then begin
944 Res := GikoSys.DivideStrLine(Body[0]);
945 ThreadItem.Title := Res.FTitle;
947 ThreadItem.Size := 0;
948 //ThreadItem.Count := 0;
949 ThreadItem.AllResCount := 0;
950 ThreadItem.NewResCount := 0;
952 NewRes := Body.Count;
959 ThreadItem.RoundDate := Now;
960 ThreadItem.Size := ThreadItem.Size + ContentLength;
961 ThreadItem.LastModified := LastModified;
962 ThreadItem.Count := Cnt;
963 ThreadItem.AllResCount := Cnt;
964 ThreadItem.NewResCount := NewRes;
965 ThreadItem.IsLogFile := True;
966 ThreadItem.NewReceive := OldCnt + 1;
967 ThreadItem.UnRead := True;
968 ThreadItem.ParentBoard.UnRead := ThreadItem.ParentBoard.UnRead + 1;
969 // if ThreadItem.RoundNo = 6 then
970 // ThreadItem.RoundNo := 0;
972 //
\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
973 //
\90³
\8fí
\8fI
\97¹
\8e\9e\82É
\82Í
\8dí
\8f\9c
974 //
\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
975 ini := TMemIniFile.Create(ChangeFileExt(FileName, '.tmp'));
977 ini.WriteDateTime('Setting', 'RoundDate', ThreadItem.RoundDate);
978 ini.WriteDateTime('Setting', 'LastModified', ThreadItem.LastModified);
979 ini.WriteInteger('Setting', 'Size', ThreadItem.Size);
980 ini.WriteInteger('Setting', 'Count', ThreadItem.Count);
981 ini.WriteInteger('Setting', 'AllResCount', ThreadItem.AllResCount);
982 ini.WriteInteger('Setting', 'NewResCount', ThreadItem.NewResCount);
983 ini.WriteInteger('Setting', 'NewReceive', ThreadItem.NewReceive);
984 // ini.WriteInteger('Setting', 'RoundNo', ThreadItem.RoundNo);
985 ini.WriteBool('Setting', 'Round', ThreadItem.Round);
986 ini.WriteBool('Setting', 'UnRead', ThreadItem.UnRead);