1 library MachiBBSPlugIn;
5 \82Ü
\82¿BBS
\8f\88\97\9d\83\86\83j
\83b
\83g
6 \95¶
\8e\9a\83R
\81[
\83h
\82Ì
\95Ï
\8a·
\82É PzConv.pas [ http://plaza11.mbn.or.jp/~pz/ ]
\82ð
\8eg
\97p
\82µ
\82Ä
\82¢
\82Ü
\82·
\81B
7 \83R
\83\93\83p
\83C
\83\8b\91O
\82É
\81A
\93¯
\82¶
\83f
\83B
\83\8c\83N
\83g
\83\8a\82É
\92u
\82¢
\82Ä
\82
\82¾
\82³
\82¢
\81B
16 YofUtils in '..\..\YofUtils.pas',
17 PlugInMain in 'PlugInMain.pas',
18 ThreadItem in 'ThreadItem.pas',
19 BoardItem in 'BoardItem.pas',
20 FilePath in 'FilePath.pas';
25 // =========================================================================
26 // TMachiBBSThreadItem
27 // =========================================================================
28 TMachiBBSThreadItem = class(TThreadItem)
30 FIsTemporary : Boolean;
34 constructor Create( inInstance : DWORD );
35 destructor Destroy; override;
38 function Download : TDownloadState;
39 function GetRes( inNo : Integer ) : string;
40 function GetHeader( inOptionalHeader : string ) : string;
41 function GetFooter( inOptionalFooter : string ) : string;
43 procedure To2chDat( ioHTML : TStringList );
46 // =========================================================================
48 // =========================================================================
49 TMachiBBSBoardItem = class(TBoardItem)
51 FIsTemporary : Boolean;
55 constructor Create( inInstance : DWORD );
56 destructor Destroy; override;
59 function Download : TDownloadState;
60 function ToThreadURL( inFileName : string ) : string;
61 procedure EnumThread( inCallBack : TBoardItemEnumThreadCallBack );
65 // =========================================================================
66 //
\83T
\83u
\83W
\83F
\83N
\83g
\83\8c\83R
\81[
\83h
67 // =========================================================================
75 LOG_DIR = 'MachiBBS\';
77 PLUGIN_NAME = 'MachiBBSPlugIn';
80 RELEASE_VERSION = 'develop';
83 // =========================================================================
85 // =========================================================================
87 // *************************************************************************
88 //
\83e
\83\93\83|
\83\89\83\8a\82È
\83p
\83X
\82Ì
\8eæ
\93¾
89 // *************************************************************************
90 function TemporaryFile : string;
92 tempPath : array [0..MAX_PATH] of char;
95 GetTempPath( SizeOf(tempPath), tempPath );
97 Result := tempPath + IntToStr( Random( $7fffffff ) );
98 until not FileExists( Result );
102 // *************************************************************************
103 //
\82Ü
\82¿BBS
\97p
\83\8d\83O
\83t
\83H
\83\8b\83_
\8eæ
\93¾
104 // *************************************************************************
105 function MyLogFolder : string;
111 if Length( folder ) = 0 then
114 Result := folder + LOG_DIR;
118 (*************************************************************************
119 *
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ª
\91¶
\8dÝ
\82·
\82é
\82©
\83`
\83F
\83b
\83N
120 *************************************************************************)
121 function DirectoryExistsEx(const Name: string): Boolean;
125 Code := GetFileAttributes(PChar(Name));
126 Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
129 (*************************************************************************
130 *
\83f
\83B
\83\8c\83N
\83g
\83\8a\8dì
\90¬
\81i
\95¡
\90\94\8aK
\91w
\91Î
\89\9e\81j
131 *************************************************************************)
132 function ForceDirectoriesEx(Dir: string): Boolean;
135 if Length(Dir) = 0 then
136 raise Exception.Create('
\83t
\83H
\83\8b\83_
\82ª
\8dì
\90¬
\8fo
\97\88\82Ü
\82¹
\82ñ');
137 Dir := ExcludeTrailingPathDelimiter(Dir);
138 if (Length(Dir) < 3) or DirectoryExistsEx(Dir)
139 or (ExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
140 Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
143 (*************************************************************************
144 *
\82Ç
\82±
\82©
\82Ì
\83T
\83C
\83g
\82©
\82ç
\82Ì
\83p
\83N
\83\8a
145 *************************************************************************)
146 function RemoveToken(var s: string; delimiter: string): string;
150 p := AnsiPos(delimiter, s);
154 Result := Copy(s, 1, p - 1);
155 s := Copy(s, Length(Result) + Length(delimiter) + 1, Length(s));
158 (*************************************************************************
159 *
\82Ç
\82±
\82©
\82Ì
\83T
\83C
\83g
\82©
\82ç
\82Ì
\83p
\83N
\83\8a
160 *************************************************************************)
161 function GetTokenIndex(s: string; delimiter: string; index: Integer): string;
166 for i := 0 to index do
167 Result := RemoveToken(s, delimiter);
170 (*************************************************************************
171 *
\95¶
\8e\9a\97ñ
\90\94\8e\9a\83`
\83F
\83b
\83N
172 *************************************************************************)
173 function IsNumeric(s: string): boolean;
182 (*************************************************************************
183 *
\83T
\83u
\83W
\83F
\83N
\83g
\88ê
\8ds
\82ð
\95ª
\8a\84
184 *************************************************************************)
185 function DivideSubject(Line: string): TSubjectRec;
195 if Pos('<>', Line) = 0 then
200 Result.FFileName := GetTokenIndex(Line, Delim, 0);
201 Result.FTitle := GetTokenIndex(Line, Delim, 1);
203 ws := Trim(Result.FTitle);
205 if Copy(ws, Length(ws), 1) = ')' then begin
208 end else if Copy(ws, Length(ws), 1) = '
\81j' then begin
211 end else if Copy(ws, Length(ws), 1) = '<' then begin
216 for i := Length(ws) - 1 downto 1 do begin
217 if ws[i] = LeftK then begin
218 ws := Copy(ws, i + 1, Length(ws) - i - 1);
219 if IsNumeric(ws) then
220 Result.FCount := StrToInt(ws);
221 Result.FTitle := Trim(StringReplace(Result.FTitle, LeftK + ws + RightK, '', [rfReplaceAll]));
229 // =========================================================================
231 // =========================================================================
233 // *************************************************************************
234 //
\83v
\83\89\83O
\83C
\83\93\82Ì
\83o
\81[
\83W
\83\87\83\93\82ð
\97v
\8b\81\82³
\82ê
\82½
235 // *************************************************************************
236 procedure OnVersionInfo(
237 var outAgent : PChar; //
\83o
\81[
\83W
\83\87\83\93\82ð
\88ê
\90Ø
\8aÜ
\82Ü
\82È
\82¢
\8f\83\90\88\82È
\96¼
\8fÌ
238 var outMajor : DWORD; //
\83\81\83W
\83\83\81[
\83o
\81[
\83W
\83\87\83\93
239 var outMinor : DWORD; //
\83}
\83C
\83i
\81[
\83o
\81[
\83W
\83\87\83\93
240 var outRelease : PChar; //
\83\8a\83\8a\81[
\83X
\92i
\8aK
\96¼
241 var outRevision : DWORD //
\83\8a\83r
\83W
\83\87\83\93\83i
\83\93\83o
\81[
246 outAgent := CreateResultString( PChar( PLUGIN_NAME ) );
247 outMajor := MAJOR_VERSION;
248 outMinor := MINOR_VERSION;
249 outRelease := CreateResultString( PChar( RELEASE_VERSION ) );
250 outRevision := REVISION_VERSION;
261 // *************************************************************************
262 //
\8ew
\92è
\82µ
\82½ URL
\82ð
\82±
\82Ì
\83v
\83\89\83O
\83C
\83\93\82Å
\8eó
\82¯
\95t
\82¯
\82é
\82©
\82Ç
\82¤
\82©
263 // *************************************************************************
264 function OnAcceptURL(
265 inURL : PChar //
\94»
\92f
\82ð
\8bÂ
\82¢
\82Å
\82¢
\82é URL
266 ): Boolean; stdcall; //
\8eó
\82¯
\95t
\82¯
\82é
\82È
\82ç True
271 BBS_HOST = 'machi.to';
275 //
\97á
\82Æ
\82µ
\82Ä
\83z
\83X
\83g
\96¼
\82ª machi.to
\82Å
\8fI
\82í
\82é
\8fê
\8d\87\82Í
\8eó
\82¯
\95t
\82¯
\82é
\82æ
\82¤
\82É
\82µ
\82Ä
\82¢
\82é
276 URI := TIdURI.Create( inURL );
278 foundPos := Pos( BBS_HOST, URI.Host );
279 Result := (foundPos > 0) and (Length( URI.Host ) - foundPos + 1 = Length( BBS_HOST ))
291 // =========================================================================
292 // TMachiBBSThreadItem
293 // =========================================================================
295 // *************************************************************************
296 //
\83R
\83\93\83X
\83g
\83\89\83N
\83^
297 // *************************************************************************
298 constructor TMachiBBSThreadItem.Create(
303 uriList : TStringList;
308 OnDownload := Download;
310 OnGetHeader := GetHeader;
311 OnGetFooter := GetFooter;
314 FIsTemporary := False;
317 uri := TIdURI.Create( URL );
318 uriList := TStringList.Create;
320 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
321 YofUtils.ExtractHttpFields(
323 Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
324 FileName := uriList.Values[ 'KEY' ] + '.dat';
325 FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
326 IsLogFile := FileExists( FilePath );
334 // *************************************************************************
335 //
\83f
\83X
\83g
\83\89\83N
\83^
336 // *************************************************************************
337 destructor TMachiBBSThreadItem.Destroy;
340 if FDat <> nil then begin
348 //
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82Ì
\8fê
\8d\87\82Í
\8dí
\8f\9c\82·
\82é
350 DeleteFile( FilePath );
356 // *************************************************************************
357 //
\8ew
\92è
\82µ
\82½ URL
\82Ì
\83X
\83\8c\83b
\83h
\82Ì
\83_
\83E
\83\93\83\8d\81[
\83h
\82ð
\8ew
\8e¦
\82³
\82ê
\82½
358 // *************************************************************************
359 function TMachiBBSThreadItem.Download : TDownloadState;
363 downResult : TStringList;
364 responseCode : Longint;
365 logStream : TFileStream;
367 uriList : TStringList;
374 uri := TIdURI.Create( URL );
375 uriList := TStringList.Create;
377 YofUtils.ExtractHttpFields(
379 Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
380 if MyLogFolder = '' then begin
381 //
\82Ç
\82±
\82É
\95Û
\91¶
\82µ
\82Ä
\82¢
\82¢
\82Ì
\82©
\95ª
\82©
\82ç
\82È
\82¢
\82Ì
\82Å
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82É
\95Û
\91¶
382 FilePath := TemporaryFile;
383 FIsTemporary := True;
385 FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
386 FIsTemporary := False;
389 //
\95Û
\91¶
\97p
\82Ì
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ð
\8c@
\82é
390 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
392 if FileExists( FilePath ) then
393 logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite )
395 logStream := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
397 //
\93Æ
\8e©
\82É
\83_
\83E
\83\93\83\8d\81[
\83h
\82â
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
398 // InternalDownload
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
399 modified := LastModified;
400 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
401 //
\90V
\92\85\82Ì
\82Ý
\8eæ
\93¾
\82·
\82é
\95û
\96@
\82Í
\96³
\82µ
403 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
404 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ];
405 responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
408 if responseCode = 200 then begin
409 downResult := TStringList.Create;
411 downResult.Text := string( tmp );
413 //
\83\8c\83X
\82Ì
\8aJ
\8en
\88Ê
\92u
414 foundPos := Pos( '<dt', downResult.Text );
415 downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
416 if foundPos > 0 then begin
417 //
\83\8c\83X
\82Ì
\8fI
\97¹
\88Ê
\92u
418 foundPos := Pos( '<table', downResult.Text ) - 1;
420 downResult.Text := Copy( downResult.Text, 1, foundPos );
422 //
\82Ü
\82¿BBS
\82Í dat
\92¼
\93Ç
\82Ý
\82ª
\8fo
\97\88\82È
\82¢
\82µ
\81Acgi
\88È
\8aO
\82É
\8d·
\95ª
\93Ç
\82Ý
\8d\9e\82Ý
\82Ì
\95û
\96@
\82ª
\82 \82é
\82í
\82¯
\82Å
\82à
\96³
\82¢
\82Ì
\82Å
423 //
\91f
\82Ì
\82Ü
\82Ü
\82ð
\96³
\97\9d\82É
\95Û
\82Æ
\82¤
\82Æ
\82Í
\82¹
\82¸
\82É 2ch
\82Ì dat
\8c`
\8e®
\82É
\95Ï
\8a·
\82µ
\82½
\82à
\82Ì
\82ð
\95Û
\91¶
\82µ
\82Ä
\82µ
\82Ü
\82¤
424 To2chDat( downResult );
426 if downResult.Count > 0 then begin
427 logStream.Position := 0;
428 logStream.Write( PChar( downResult.Text )^, Length( downResult.Text ) );
429 logStream.Size := Length( downResult.Text );
431 if AllResCount <> downResult.Count then begin
432 if AllResCount = 0 then
435 Result := dsDiffComplete;
436 LastModified := modified;
438 NewReceive := Count + 1;
439 NewResCount := downResult.Count - Count;
440 Count := downResult.Count;
442 Result := dsNotModify;
451 DisposeResultString( tmp );
463 // *************************************************************************
464 //
\83\8c\83X
\94Ô
\8d\86 inNo
\82É
\91Î
\82·
\82é html
\82ð
\97v
\8b\81\82³
\82ê
\82½
465 // *************************************************************************
466 function TMachiBBSThreadItem.GetRes(
467 inNo : Integer //
\97v
\8b\81\82³
\82ê
\82½
\83\8c\83X
\94Ô
\8d\86
468 ) : string; //
\91Î
\89\9e\82·
\82é HTML
474 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
475 // InternalAbon
\82¨
\82æ
\82Ñ Dat2HTML
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
476 if FDat = nil then begin
477 if IsLogFile then begin
478 // dat
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
479 FDat := TStringList.Create;
480 FDat.LoadFromFile( FilePath );
482 AllResCount := FDat.Count; //
\96{
\93\96\82Í
\82±
\82±
\82Å
\82â
\82é
\82×
\82«
\82Å
\82Í
\82È
\82¢
\82ª
\8eÀ
\8c±
\82Ì
\82½
\82ß
\82Ì
\88ê
\8e\9e\93I
\82È
\82à
\82Ì
484 //
\83\8d\83O
\82É
\91¶
\8dÝ
\82µ
\82È
\82¢
\82Ì
\82Å
\82±
\82Ì
\82Ü
\82Ü
\8fI
\97¹
489 res := FDat[ inNo - 1 ];
490 tmp := InternalAbon( PChar( res ) );
492 Result := Dat2HTML( string( tmp ), inNo );
494 DisposeResultString( tmp );
499 // *************************************************************************
500 //
\83X
\83\8c\83b
\83h
\82Ì
\83w
\83b
\83_ html
\82ð
\97v
\8b\81\82³
\82ê
\82½
501 // *************************************************************************
502 function TMachiBBSThreadItem.GetHeader(
503 inOptionalHeader : string
507 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
508 // InternalHeader
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
509 Result := InternalHeader(
510 '<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">' +
514 // GetRes
\82ð
\8cÄ
\82Î
\82ê
\82é
\82±
\82Æ
\82ª
\97\
\91z
\82³
\82ê
\82é
\82Ì
\82Å FDat
\82ð
\90¶
\90¬
\82µ
\82Ä
\82¨
\82
515 if FDat <> nil then begin
522 if IsLogFile then begin
523 // dat
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
524 FDat := TStringList.Create;
525 FDat.LoadFromFile( FilePath );
530 // *************************************************************************
531 //
\83X
\83\8c\83b
\83h
\82Ì
\83t
\83b
\83^ html
\82ð
\97v
\8b\81\82³
\82ê
\82½
532 // *************************************************************************
533 function TMachiBBSThreadItem.GetFooter(
534 inOptionalFooter : string
538 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
539 // InternalFooter
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
540 Result := InternalFooter( inOptionalFooter );
542 //
\82à
\82¤ GetRes
\82Í
\8cÄ
\82Î
\82ê
\82È
\82¢
\82Æ
\8ev
\82¤
\82Ì
\82Å FDat
\82ð
\8aJ
\95ú
\82µ
\82Ä
\82¨
\82
544 if FDat <> nil then begin
553 // *************************************************************************
554 //
\82Ü
\82¿BBS
\82Ì HTML
\82ð 2ch
\82Ì dat
\8c`
\8e®
\82É
555 // *************************************************************************
556 procedure TMachiBBSThreadItem.To2chDat(
565 MAIL_TAG = '<a href="mailto:';
568 //===== 2ch
\82Ì dat
\8c`
\8e®
\82É
\95Ï
\8a·
569 //
\83z
\83X
\83g
\96¼
\82Ì
\8cã
\82Å
\89ü
\8ds
\82³
\82ê
\82Ä
\82¢
\82½
\82è
\82·
\82é
\82Ì
\82Å
\89ü
\8ds
\82ð
\82·
\82×
\82Ä
\8eæ
\82è
\8f\9c\82
570 ioHTML.Text := StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
571 //
\91ã
\82í
\82è
\82É <dt>
\82ð
\8ds
\82Ì
\8bæ
\90Ø
\82è
\82É
\82·
\82é
572 ioHTML.Text := StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
573 // <dt>
\82©
\82ç
\8en
\82Ü
\82Á
\82Ä
\82¢
\82é
\82Ì
\82Å
\8dÅ
\8f\89\82Í
\8bó
\82Ì
\82Í
\82¸
574 if Length( ioHTML[ 0 ] ) = 0 then
576 //
\83g
\83\8a\83b
\83v
\82Ì
\8cã
\82Ì '<b> </b>'
\82ð
\8bó
\82É
577 ioHTML.Text := StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
578 // '<b>'
\82Í
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82Ì
\8bæ
\90Ø
\82è
579 ioHTML.Text := StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
580 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82É
\82Â
\82¢
\82Ä
\82
\82é
\95Â
\82¶
\83^
\83O
\82ð
\93\8a\8de
\93ú
\82Æ
\82Ì
\8bæ
\90Ø
\82è
\82É
581 ioHTML.Text := StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
582 ioHTML.Text := StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
583 // '<dd>'
\82ð
\96{
\95¶
\82Æ
\82Ì
\8bæ
\90Ø
\82è
\82É
584 ioHTML.Text := StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
586 res := TStringList.Create;
588 bound := ioHTML.Count - 1;
589 for i := 0 to bound do begin
590 res.Text := StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
591 if res.Count >= 3 then begin // 3
\96¢
\96\9e\82Í
\82 \82è
\82¦
\82È
\82¢
\82Æ
\8ev
\82¤
\82¯
\82Ç
\88À
\91S
\82Ì
\82½
\82ß
592 foundPos := Pos( MAIL_TAG, res[ 0 ] );
593 if foundPos > 0 then begin
594 //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
\82ð
\94²
\82«
\8fo
\82·
595 foundPos := foundPos + Length( MAIL_TAG );
596 res[ 0 ] := Copy( res[ 0 ], foundPos, Length( res[ 0 ] ) );
597 strTmp := Copy( res[ 0 ], 1, Pos( '">', res[ 0 ] ) - 1 );
598 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82ª
\8bt
\82È
\82Ì
\82Å
\82Ð
\82Á
\82
\82è
\95Ô
\82µ
\82Ä
\96ß
\82·
599 res[ 0 ] := res[ 1 ];
602 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82ª
\8bt
\82È
\82Ì
\82Å
\82Ð
\82Á
\82
\82è
\95Ô
\82·
603 res[ 0 ] := res[ 1 ];
606 res[ 2 ] := StringReplace( res[ 2 ], '[', 'ID:', [] );
607 res[ 2 ] := StringReplace( res[ 2 ], ']', '', [] );
609 ioHTML[ i ] := StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
617 // *************************************************************************
618 // TThreadItem
\82ª
\90¶
\90¬
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSThreadItem
\82ð
\90¶
\90¬
\82·
\82é)
619 // *************************************************************************
620 procedure ThreadItemOnCreateOfTMachiBBSThreadItem(
624 threadItem : TMachiBBSThreadItem;
627 threadItem := TMachiBBSThreadItem.Create( inInstance );
628 ThreadItemSetLong( inInstance, tipContext, DWORD( threadItem ) );
632 // *************************************************************************
633 // TThreadItem
\82ª
\94j
\8aü
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSThreadItem
\82ð
\94j
\8aü
\82·
\82é)
634 // *************************************************************************
635 procedure ThreadItemOnDisposeOfTMachiBBSThreadItem(
639 threadItem : TMachiBBSThreadItem;
642 threadItem := TMachiBBSThreadItem( ThreadItemGetLong( inInstance, tipContext ) );
647 // =========================================================================
648 // TMachiBBSBoardItem
649 // =========================================================================
651 // *************************************************************************
652 //
\83R
\83\93\83X
\83g
\83\89\83N
\83^
653 // *************************************************************************
654 constructor TMachiBBSBoardItem.Create(
659 uriList : TStringList;
664 OnDownload := Download;
665 OnEnumThread := EnumThread;
666 OnFileName2ThreadURL := ToThreadURL;
669 FIsTemporary := False;
672 if Copy( URL, Length( URL ), 1 ) = '/' then
673 uri := TIdURI.Create( URL )
675 uri := TIdURI.Create( URL + '/' );
676 uriList := TStringList.Create;
678 YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
679 // http://hokkaido.machi.to/hokkaidou/subject.txt
680 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
681 IsLogFile := FileExists( FilePath );
689 // *************************************************************************
690 //
\83f
\83X
\83g
\83\89\83N
\83^
691 // *************************************************************************
692 destructor TMachiBBSBoardItem.Destroy;
695 if FDat <> nil then begin
703 //
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82Ì
\8fê
\8d\87\82Í
\8dí
\8f\9c\82·
\82é
705 DeleteFile( FilePath );
711 // *************************************************************************
712 //
\8ew
\92è
\82µ
\82½
\83X
\83\8c\88ê
\97\97\82Ì
\83_
\83E
\83\93\83\8d\81[
\83h
\82ð
\97v
\8b\81\82³
\82ê
\82½
713 // *************************************************************************
714 function TMachiBBSBoardItem.Download : TDownloadState;
718 responseCode : Longint;
720 uriList : TStringList;
722 SUBJECT_NAME = 'subject.txt';
727 if Copy( URL, Length( URL ), 1 ) = '/' then
728 uri := TIdURI.Create( URL + SUBJECT_NAME )
730 uri := TIdURI.Create( URL );
731 uriList := TStringList.Create;
732 if FDat <> nil then begin
739 FDat := TStringList.Create;
740 //
\93Æ
\8e©
\82É
\83_
\83E
\83\93\83\8d\81[
\83h
\82â
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
741 // InternalDownload
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
742 modified := LastModified;
743 responseCode := InternalDownload( PChar( uri.URI ), modified, downResult );
745 if responseCode = 200 then begin
747 //
\83p
\83X
\82ð
\8eZ
\8fo
748 YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
749 if MyLogFolder = '' then begin
750 //
\82Ç
\82±
\82É
\95Û
\91¶
\82µ
\82Ä
\82¢
\82¢
\82Ì
\82©
\95ª
\82©
\82ç
\82È
\82¢
\82Ì
\82Å
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82É
\95Û
\91¶
751 FilePath := TemporaryFile;
752 FIsTemporary := True;
754 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
755 FIsTemporary := False
758 //
\95Û
\91¶
\97p
\82Ì
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ð
\8c@
\82é
759 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
761 FDat.Text := string( downResult );
763 FDat.SaveToFile( FilePath );
768 Result := dsComplete;
771 DisposeResultString( downResult );
776 // *************************************************************************
777 //
\83X
\83\8c\88ê
\97\97\82Ì URL
\82©
\82ç
\83X
\83\8c\83b
\83h
\82Ì URL
\82ð
\93±
\82«
\8fo
\82·
778 // *************************************************************************
779 function TMachiBBSBoardItem.ToThreadURL(
780 inFileName : string //
\83X
\83\8c\83b
\83h
\83t
\83@
\83C
\83\8b\96¼
781 ) : string; //
\83X
\83\8c\83b
\83h
\82Ì URL
785 uriList : TStringList;
789 found := Pos( '.', inFileName );
791 inFileName := Copy( inFileName, 1, found - 1 );
792 if Copy( URL, Length( URL ), 1 ) = '/' then
793 uri := TIdURI.Create( URL )
795 uri := TIdURI.Create( URL + '/' );
796 uriList := TStringList.Create;
800 // http://hokkaido.machi.to/hokkaidou/
801 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
802 YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
803 threadURL := uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
804 'BBS=' + uriList[ 1 ] + '&KEY=' + inFileName + '&LAST=50';
816 // *************************************************************************
817 //
\82±
\82Ì
\94Â
\82É
\82¢
\82
\82Â
\82Ì
\83X
\83\8c\82ª
\82 \82é
\82©
\97v
\8b\81\82³
\82ê
\82½
818 // *************************************************************************
819 procedure TMachiBBSBoardItem.EnumThread(
820 inCallBack : TBoardItemEnumThreadCallBack
824 uriList : TStringList;
827 isContinue : Boolean;
829 SUBJECT_NAME = 'subject.txt';
833 if FDat = nil then begin
834 FDat := TStringList.Create;
836 if Copy( URL, Length( URL ), 1 ) = '/' then
837 uri := TIdURI.Create( URL + SUBJECT_NAME )
839 uri := TIdURI.Create( URL );
840 uriList := TStringList.Create;
842 //
\83p
\83X
\82ð
\8eZ
\8fo
843 YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
844 // http://hokkaido.machi.to/hokkaidou/subject.txt
845 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
846 if FileExists( FilePath ) then
847 //
\93Ç
\82Ý
\8d\9e\82Ý
848 FDat.LoadFromFile( FilePath );
855 for i := 0 to FDat.Count - 1 do begin
856 rec := DivideSubject( FDat[i] );
857 rec.FFileName := Trim(rec.FFileName);
858 if (rec.FTitle = '') and (rec.FCount = 0) then
861 isContinue := inCallBack(
863 PChar( ToThreadURL( rec.FFileName ) ),
865 DWORD( rec.FCount ) );
867 if ( not isContinue ) then
875 // *************************************************************************
876 // TBoardItem
\82ª
\90¶
\90¬
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSBoardItem
\82ð
\90¶
\90¬
\82·
\82é)
877 // *************************************************************************
878 procedure BoardItemOnCreateOfTMachiBBSBoardItem(
882 boardItem : TMachiBBSBoardItem;
885 boardItem := TMachiBBSBoardItem.Create( inInstance );
886 BoardItemSetLong( inInstance, bipContext, DWORD( boardItem ) );
890 // *************************************************************************
891 // TBoardItem
\82ª
\94j
\8aü
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSBoardItem
\82ð
\94j
\8aü
\82·
\82é)
892 // *************************************************************************
893 procedure BoardItemOnDisposeOfTMachiBBSBoardItem(
897 boardItem : TMachiBBSBoardItem;
900 boardItem := TMachiBBSBoardItem( BoardItemGetLong( inInstance, bipContext ) );
907 // =========================================================================
908 //
\83G
\83\93\83g
\83\8a\83|
\83C
\83\93\83g
909 // =========================================================================
911 ul_reason_for_call : DWORD
917 case ul_reason_for_call of
922 module := GetModuleHandle( nil );
924 LoadInternalAPI( module );
925 LoadInternalFilePathAPI( module );
926 LoadInternalThreadItemAPI( module );
927 LoadInternalBoardItemAPI( module );
929 // =====
\83C
\83\93\83X
\83^
\83\93\83X
\82Ì
\8eæ
\82è
\88µ
\82¢
\82ð TThreadItem
\82©
\82ç TMachiBBSThreadItem
\82É
\95Ï
\8dX
\82·
\82é
930 ThreadItemOnCreate := ThreadItemOnCreateOfTMachiBBSThreadItem;
931 ThreadItemOnDispose := ThreadItemOnDisposeOfTMachiBBSThreadItem;
932 // =====
\83C
\83\93\83X
\83^
\83\93\83X
\82Ì
\8eæ
\82è
\88µ
\82¢
\82ð TBoardItem
\82©
\82ç TMachiBBSBoardItem
\82É
\95Ï
\8dX
\82·
\82é
933 BoardItemOnCreate := BoardItemOnCreateOfTMachiBBSBoardItem;
934 BoardItemOnDispose := BoardItemOnDisposeOfTMachiBBSBoardItem;
953 DllProc := @DLLEntry;
954 DLLEntry( DLL_PROCESS_ATTACH );