1 library MachiBBSPlugIn;
5 \82Ü
\82¿BBS
\8f\88\97\9d\83\86\83j
\83b
\83g
9 Windows, SysUtils, Classes, Math, DateUtils,
11 PlugInMain in 'PlugInMain.pas',
12 ThreadItem in 'ThreadItem.pas',
13 BoardItem in 'BoardItem.pas',
14 FilePath in 'FilePath.pas',
15 MojuUtils in '..\..\MojuUtils.pas';
20 // =========================================================================
21 // TMachiBBSThreadItem
22 // =========================================================================
23 TMachiBBSThreadItem = class(TThreadItem)
25 FIsTemporary : Boolean;
29 constructor Create( inInstance : DWORD );
30 destructor Destroy; override;
33 function Download : TDownloadState;
34 function Write( inName : string; inMail : string; inMessage : string ) : TDownloadState;
35 function GetRes( inNo : Integer ) : string;
36 function GetDat( inNo : Integer ) : string;
37 function GetHeader( inOptionalHeader : string ) : string;
38 function GetFooter( inOptionalFooter : string ) : string;
39 function GetBoardURL : string;
41 procedure To2chDat( ioHTML : TStringList; inStartNo : Integer = 1 );
44 function ReadURL : string;
47 // =========================================================================
49 // =========================================================================
50 TMachiBBSBoardItem = class(TBoardItem)
52 FIsTemporary : Boolean;
56 constructor Create( inInstance : DWORD );
57 destructor Destroy; override;
60 function Download : TDownloadState;
61 function CreateThread( inSubject : string; inName : string; inMail : string; inMessage : string ) : TDownloadState;
62 function ToThreadURL( inFileName : string ) : string;
63 procedure EnumThread( inCallBack : TBoardItemEnumThreadCallBack );
65 function SubjectURL : string;
68 // =========================================================================
69 //
\83T
\83u
\83W
\83F
\83N
\83g
\83\8c\83R
\81[
\83h
70 // =========================================================================
78 LOG_DIR = 'MachiBBS\';
79 SUBJECT_NAME = 'subject.txt';
81 PLUGIN_NAME = 'MachiBBSPlugIn';
84 RELEASE_VERSION = 'beta';
85 REVISION_VERSION = 11;
87 // =========================================================================
89 // =========================================================================
91 // *************************************************************************
92 //
\83e
\83\93\83|
\83\89\83\8a\82È
\83p
\83X
\82Ì
\8eæ
\93¾
93 // *************************************************************************
94 function TemporaryFile : string;
96 tempPath : array [0..MAX_PATH] of char;
99 GetTempPath( SizeOf(tempPath), tempPath );
101 Result := tempPath + IntToStr( Random( $7fffffff ) );
102 until not FileExists( Result );
106 // *************************************************************************
107 //
\82Ü
\82¿BBS
\97p
\83\8d\83O
\83t
\83H
\83\8b\83_
\8eæ
\93¾
108 // *************************************************************************
109 function MyLogFolder : string;
115 if Length( folder ) = 0 then
118 Result := folder + LOG_DIR;
122 (*************************************************************************
123 *
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ª
\91¶
\8dÝ
\82·
\82é
\82©
\83`
\83F
\83b
\83N
124 *************************************************************************)
125 function DirectoryExistsEx(const Name: string): Boolean;
129 Code := GetFileAttributes(PChar(Name));
130 Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
133 (*************************************************************************
134 *
\83f
\83B
\83\8c\83N
\83g
\83\8a\8dì
\90¬
\81i
\95¡
\90\94\8aK
\91w
\91Î
\89\9e\81j
135 *************************************************************************)
136 function ForceDirectoriesEx(Dir: string): Boolean;
139 if Length(Dir) = 0 then
140 raise Exception.Create('
\83t
\83H
\83\8b\83_
\82ª
\8dì
\90¬
\8fo
\97\88\82Ü
\82¹
\82ñ');
141 Dir := ExcludeTrailingPathDelimiter(Dir);
142 if (Length(Dir) < 3) or DirectoryExistsEx(Dir)
143 or (ExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
144 Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
147 //
\82Æ
\82è
\82 \82¦
\82¸
\82Ì
\91ã
\97p
\95i
\82È
\82Ì
\82Å chrWhite
\82ð
\8dl
\97¶
\82µ
\82Ä
\82¢
\82È
\82¢
\82±
\82Æ
\82É
\92\8d\88Ó
\81I
\81I
\81I
148 procedure ExtractHttpFields(
149 const chrSep : TSysCharSet;
150 const chrWhite : TSysCharSet;
151 const strValue : string;
152 var strResult : TStringList;
153 unknownFlag : boolean = false
156 last, p, strLen : Integer;
159 strLen := Length( strValue );
166 if strValue[ p ] in chrSep then
168 strResult.Add( Copy( strValue, last, p - last ) );
177 strResult.Add( Copy( strValue, last, strLen - last + 1 ) );
181 \rfunction HttpEncode(
182 \r const strValue : string
190 kHexCode : array [0..15] of char = (
191 '0', '1', '2', '3', '4', '5', '6', '7',
192 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' );
195 strLen := Length( strValue );
201 case strValue[ i ] of
202 '0' .. '9', 'a' .. 'z', 'A' .. 'Z', '*', '-', '.', '@', '_':
204 strResult := strResult + strValue[ i ];
208 b := Integer( strValue[ i ] );
209 strResult := strResult + '%'
210 + kHexCode[ b div $10 ]
211 + kHexCode[ b mod $10 ];
225 // =========================================================================
227 // =========================================================================
229 // *************************************************************************
230 //
\83v
\83\89\83O
\83C
\83\93\82Ì
\83o
\81[
\83W
\83\87\83\93\82ð
\97v
\8b\81\82³
\82ê
\82½
231 // *************************************************************************
232 procedure OnVersionInfo(
233 var outAgent : PChar; //
\83o
\81[
\83W
\83\87\83\93\82ð
\88ê
\90Ø
\8aÜ
\82Ü
\82È
\82¢
\8f\83\90\88\82È
\96¼
\8fÌ
234 var outMajor : DWORD; //
\83\81\83W
\83\83\81[
\83o
\81[
\83W
\83\87\83\93
235 var outMinor : DWORD; //
\83}
\83C
\83i
\81[
\83o
\81[
\83W
\83\87\83\93
236 var outRelease : PChar; //
\83\8a\83\8a\81[
\83X
\92i
\8aK
\96¼
237 var outRevision : DWORD //
\83\8a\83r
\83W
\83\87\83\93\83i
\83\93\83o
\81[
242 outAgent := CreateResultString( PChar( PLUGIN_NAME ) );
243 outMajor := MAJOR_VERSION;
244 outMinor := MINOR_VERSION;
245 outRelease := CreateResultString( PChar( RELEASE_VERSION ) );
246 outRevision := REVISION_VERSION;
257 // *************************************************************************
258 //
\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©
259 // *************************************************************************
260 function OnAcceptURL(
261 inURL : PChar //
\94»
\92f
\82ð
\8bÂ
\82¢
\82Å
\82¢
\82é URL
262 ): TAcceptType; stdcall; // URL
\82Ì
\8eí
\97Þ
265 uriList : TStringList;
268 BBS_HOST = 'machi.to';
269 THREAD_MARK = '/bbs/read.pl';
273 //
\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é
274 uri := TIdURI.Create( inURL );
275 uriList := TStringList.Create;
277 ExtractHttpFields( ['/'], [], uri.Path, uriList );
278 foundPos := AnsiPos( BBS_HOST, uri.Host );
279 if (foundPos > 0) and (Length( uri.Host ) - foundPos + 1 = Length( BBS_HOST )) then begin
280 foundPos := Pos( THREAD_MARK, inURL );
283 else if (uriList.Count > 1) and (uri.Path <> '/') then //
\8dÅ
\8cã
\82ª '/'
\82Å
\95Â
\82ß
\82ç
\82ê
\82Ä
\82é
\82È
\82ç 3
288 Result := atNoAccept;
295 Result := atNoAccept;
302 // =========================================================================
303 // TMachiBBSThreadItem
304 // =========================================================================
306 // *************************************************************************
307 //
\83R
\83\93\83X
\83g
\83\89\83N
\83^
308 // *************************************************************************
309 constructor TMachiBBSThreadItem.Create(
314 uriList : TStringList;
319 OnDownload := Download;
323 OnGetHeader := GetHeader;
324 OnGetFooter := GetFooter;
325 OnGetBoardURL := GetBoardURL;
328 FIsTemporary := False;
330 URL := ReadURL + '&LAST=50';
332 uri := TIdURI.Create( URL );
333 uriList := TStringList.Create;
335 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
338 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
339 FileName := uriList.Values[ 'KEY' ] + '.dat';
340 FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
341 IsLogFile := FileExists( FilePath );
349 // *************************************************************************
350 //
\83f
\83X
\83g
\83\89\83N
\83^
351 // *************************************************************************
352 destructor TMachiBBSThreadItem.Destroy;
357 //
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82Ì
\8fê
\8d\87\82Í
\8dí
\8f\9c\82·
\82é
359 DeleteFile( FilePath );
365 // *************************************************************************
366 //
\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½
367 // *************************************************************************
368 function TMachiBBSThreadItem.Download : TDownloadState;
372 downResult : TStringList;
373 content : TStringList;
374 responseCode : Longint;
375 logStream : TFileStream;
377 uriList : TStringList;
380 procedure downAndParse;
382 responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
385 if responseCode = 200 then begin
386 downResult := TStringList.Create;
388 downResult.Text := string( tmp );
390 //
\83^
\83C
\83g
\83\8b\82Ì
\8eæ
\93¾
391 foundPos := AnsiPos( '<title>', downResult.Text ) + Length( '<title>' );
395 AnsiPos( '</title>', downResult.Text ) - foundPos );
397 //
\83\8c\83X
\82Ì
\8aJ
\8en
\88Ê
\92u
398 foundPos := AnsiPos( '<dt', downResult.Text );
399 downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
400 if foundPos > 0 then begin
401 //
\83\8c\83X
\82Ì
\8fI
\97¹
\88Ê
\92u
402 foundPos := AnsiPos( '<table', downResult.Text ) - 1;
404 downResult.Text := Copy( downResult.Text, 1, foundPos );
406 //
\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Å
407 //
\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¤
408 To2chDat( downResult, Count + 1 );
409 content.Text := content.Text + downResult.Text;
415 Result := dsNotModify;
419 DisposeResultString( tmp );
426 uri := TIdURI.Create( URL );
427 uriList := TStringList.Create;
428 content := TStringList.Create;
432 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
433 FileName := uriList.Values[ 'KEY' ] + '.dat';
434 if MyLogFolder = '' then begin
435 //
\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¶
436 FilePath := TemporaryFile;
437 FIsTemporary := True;
439 FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
440 FIsTemporary := False;
443 //
\95Û
\91¶
\97p
\82Ì
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ð
\8c@
\82é
444 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
446 //
\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Í
447 // InternalDownload
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
448 modified := LastModified;
452 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
453 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
454 '&START=' + IntToStr( 1 )
456 //
\90V
\92\85\82Ì
\82Ý
458 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
459 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
460 '&START=' + IntToStr( Count + 1 ) + '&NOFIRST=TRUE';
461 //
\83_
\83E
\83\93\83\8d\81[
\83h
464 if content.Count > 0 then begin
465 if Count <= 0 then begin
466 Result := dsComplete;
467 //
\90V
\8bK
\8f\91\82«
\8d\9e\82Ý
468 content[ 0 ] := content[ 0 ] + Title;
469 logStream := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
471 logStream.Position := logStream.Size;
472 logStream.Write( PChar( content.Text )^, Length( content.Text ) );
477 Count := content.Count;
479 Result := dsDiffComplete;
481 logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite );
483 logStream.Position := logStream.Size;
484 logStream.Write( PChar( content.Text )^, Length( content.Text ) );
488 NewReceive := Count + 1;
489 Count := Count + content.Count;
492 // CGI
\82©
\82ç
\82Í
\90³
\82µ
\82¢
\93ú
\95t
\82ª
\93¾
\82ç
\82ê
\82È
\82¢
\82Ì
\82Å
\8c»
\8dÝ
\82É
\90Ý
\92è
494 NewResCount := content.Count;
496 Result := dsNotModify;
506 // *************************************************************************
507 //
\8f\91\82«
\8d\9e\82Ý
\82ð
\8ew
\8e¦
\82³
\82ê
\82½
508 // *************************************************************************
509 function TMachiBBSThreadItem.Write(
510 inName : string; //
\96¼
\91O(
\83n
\83\93\83h
\83\8b)
511 inMail : string; //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
512 inMessage : string //
\96{
\95¶
513 ) : TDownloadState; //
\8f\91\82«
\8d\9e\82Ý
\82ª
\90¬
\8c÷
\82µ
\82½
\82©
\82Ç
\82¤
\82©
519 uriList : TStringList;
522 uri := TIdURI.Create( URL );
523 uriList := TStringList.Create;
527 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
529 postURL := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
531 'NAME=' + HttpEncode( inName ) +
532 '&MAIL=' + HttpEncode( inMail ) +
533 '&MESSAGE=' + HttpEncode( inMessage ) +
534 '&BBS=' + uriList.Values[ 'BBS' ] +
535 '&KEY=' + uriList.Values[ 'KEY' ] +
536 '&TIME=' + IntToStr( DateTimeToUnix( Now ) ) +
537 '&submit=' + HttpEncode( '
\8f\91\82«
\8d\9e\82Þ' );
539 //
\93Æ
\8e©
\82É
\92Ê
\90M
\82µ
\82È
\82¢
\8fê
\8d\87\82Í InternalPost
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
540 InternalPost( PChar( postURL ), PChar( postData ), postResult );
541 DisposeResultString( postResult );
551 // *************************************************************************
552 //
\83\8c\83X
\94Ô
\8d\86 inNo
\82É
\91Î
\82·
\82é html
\82ð
\97v
\8b\81\82³
\82ê
\82½
553 // *************************************************************************
554 function TMachiBBSThreadItem.GetRes(
555 inNo : Integer //
\97v
\8b\81\82³
\82ê
\82½
\83\8c\83X
\94Ô
\8d\86
556 ) : string; //
\91Î
\89\9e\82·
\82é HTML
562 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
563 // InternalAbon
\82¨
\82æ
\82Ñ Dat2HTML
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
565 if FDat = nil then begin
566 //
\83\8d\83O
\82É
\91¶
\8dÝ
\82µ
\82È
\82¢
\82Ì
\82Å
\82±
\82Ì
\82Ü
\82Ü
\8fI
\97¹
570 res := FDat[ inNo - 1 ];
571 tmp := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
573 Result := Dat2HTML( string( tmp ), inNo );
575 DisposeResultString( tmp );
580 // *************************************************************************
581 //
\83\8c\83X
\94Ô
\8d\86 inNo
\82É
\91Î
\82·
\82é Dat
\82ð
\97v
\8b\81\82³
\82ê
\82½
582 // *************************************************************************
583 function TMachiBBSThreadItem.GetDat(
584 inNo : Integer //
\97v
\8b\81\82³
\82ê
\82½
\83\8c\83X
\94Ô
\8d\86
585 ) : string; //
\82Q
\82¿
\82á
\82ñ
\82Ë
\82é
\82ÌDat
\8c`
\8e®
588 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
590 if FDat = nil then begin
591 //
\83\8d\83O
\82É
\91¶
\8dÝ
\82µ
\82È
\82¢
\82Ì
\82Å
\82±
\82Ì
\82Ü
\82Ü
\8fI
\97¹
596 Result := FDat[ inNo - 1 ];
603 // *************************************************************************
604 //
\83X
\83\8c\83b
\83h
\82Ì
\83w
\83b
\83_ html
\82ð
\97v
\8b\81\82³
\82ê
\82½
605 // *************************************************************************
606 function TMachiBBSThreadItem.GetHeader(
607 inOptionalHeader : string
611 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
612 // InternalHeader
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
613 Result := InternalHeader(
614 '<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">' +
618 // GetRes
\82ð
\8cÄ
\82Î
\82ê
\82é
\82±
\82Æ
\82ª
\97\
\91z
\82³
\82ê
\82é
\82Ì
\82Å FDat
\82ð
\90¶
\90¬
\82µ
\82Ä
\82¨
\82
627 // *************************************************************************
628 //
\83X
\83\8c\83b
\83h
\82Ì
\83t
\83b
\83^ html
\82ð
\97v
\8b\81\82³
\82ê
\82½
629 // *************************************************************************
630 function TMachiBBSThreadItem.GetFooter(
631 inOptionalFooter : string
635 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
636 // InternalFooter
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
637 Result := InternalFooter( inOptionalFooter );
639 //
\82à
\82¤ GetRes
\82Í
\8cÄ
\82Î
\82ê
\82È
\82¢
\82Æ
\8ev
\82¤
\82Ì
\82Å FDat
\82ð
\8aJ
\95ú
\82µ
\82Ä
\82¨
\82
647 // *************************************************************************
648 //
\82±
\82Ì ThreadItem
\82ª
\91®
\82·
\82é
\94Â
\82Ì URL
\82ð
\97v
\8b\81\82³
\82ê
\82½
649 // *************************************************************************
650 function TMachiBBSThreadItem.GetBoardURL : string;
653 uriList : TStringList;
656 if Copy( URL, Length( URL ), 1 ) = '/' then
657 uri := TIdURI.Create( URL )
659 uri := TIdURI.Create( URL + '/' );
660 uriList := TStringList.Create;
664 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
665 FileName := uriList.Values[ 'KEY' ] + '.dat';
666 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
667 // http://hokkaido.machi.to/hokkaidou/
668 Result := CreateResultString(
669 uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/' );
677 // *************************************************************************
678 //
\82Ü
\82¿BBS
\82Ì HTML
\82ð 2ch
\82Ì dat
\8c`
\8e®
\82É
679 // *************************************************************************
680 procedure TMachiBBSThreadItem.To2chDat(
681 ioHTML : TStringList;
682 inStartNo : Integer = 1
691 MAIL_TAG = '<a href="mailto:';
694 //===== 2ch
\82Ì dat
\8c`
\8e®
\82É
\95Ï
\8a·
695 //
\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
696 ioHTML.Text := CustomStringReplace( ioHTML.Text, #13#10, '');
697 //StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
698 //
\91ã
\82í
\82è
\82É <dt>
\82ð
\8ds
\82Ì
\8bæ
\90Ø
\82è
\82É
\82·
\82é
699 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<dt>', #10 );
700 //StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
701 // <dt>
\82©
\82ç
\8en
\82Ü
\82Á
\82Ä
\82¢
\82é
\82Ì
\82Å
\8dÅ
\8f\89\82Í
\8bó
\82Ì
\82Í
\82¸
702 if Length( ioHTML[ 0 ] ) = 0 then
705 //
\8cy
\82
\82 \82Ú
\81[
\82ñ
\83`
\83F
\83b
\83N
706 //
\81¦
\91å
\8eG
\94c
\82¾
\82©
\82ç
\82¿
\82á
\82ñ
\82Æ
\8fo
\97\88\82Ä
\82È
\82¢
\82©
\82à
709 while i < ioHTML.Count do begin
710 foundPos := AnsiPos( ' ', ioHTML[ i ] );
711 if foundPos > 0 then begin
712 no := StrToInt( Copy( ioHTML[ i ], 1, foundPos - 1 ) );
713 if inStartNo < no then
714 ioHTML.Insert( i, '<><><><>' );
720 //
\82 \82Ú
\81[
\82ñ
\83`
\83F
\83b
\83N
\82Å
\96â
\91è
\82ª
\94
\90¶
\82µ
\82Ä
\82à
\90æ
\82Ö
\90i
\82ß
\82½
\82¢
\82Ì
\82Å
723 //
\83g
\83\8a\83b
\83v
\82Ì
\8cã
\82Ì '<b> </b>'
\82ð
\8bó
\82É
724 if AnsiPos('
\81\9f</b>', ioHTML.Text) <> 0 then begin
725 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </b></font>', '</b></font>', true );
726 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </B></a>', '</b></a>', true );
728 //ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </b>', '', true );
729 //StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
730 // '<b>'
\82Í
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82Ì
\8bæ
\90Ø
\82è
731 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b>', '<>', true );
732 //StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
733 //
\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É
734 ioHTML.Text := CustomStringReplace( ioHTML.Text, '</b></a>', '<>', true );
735 //StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
736 ioHTML.Text := CustomStringReplace( ioHTML.Text, '</b>', '<>', true );
737 ioHTML.Text := CustomStringReplace( ioHTML.Text, '
\81\9f<>', '
\81\9f</b>', true );
738 //StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
739 // '<dd>'
\82ð
\96{
\95¶
\82Æ
\82Ì
\8bæ
\90Ø
\82è
\82É
740 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<dd>', '<>', true );
741 //StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
743 res := TStringList.Create;
745 bound := ioHTML.Count - 1;
746 for i := 0 to bound do begin
747 res.Text := CustomStringReplace( ioHTML[ i ], '<>', #10 );
748 //StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
749 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ß
750 foundPos := AnsiPos( MAIL_TAG, res[ 0 ] );
751 if foundPos > 0 then begin
752 //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
\82ð
\94²
\82«
\8fo
\82·
753 foundPos := foundPos + Length( MAIL_TAG );
754 res[ 0 ] := Copy( res[ 0 ], foundPos, Length( res[ 0 ] ) );
755 strTmp := Copy( res[ 0 ], 1, AnsiPos( '">', res[ 0 ] ) - 1 );
756 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82ª
\8bt
\82È
\82Ì
\82Å
\82Ð
\82Á
\82
\82è
\95Ô
\82µ
\82Ä
\96ß
\82·
757 res[ 0 ] := res[ 1 ];
760 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82ª
\8bt
\82È
\82Ì
\82Å
\82Ð
\82Á
\82
\82è
\95Ô
\82·
761 res[ 0 ] := res[ 1 ];
764 res[ 2 ] := StringReplace( res[ 2 ], '[', 'IP:', [] );
765 res[ 2 ] := StringReplace( res[ 2 ], ']', '', [] );
767 if AnsiPos('</font>
\93\8a\8de
\93ú
\81F', res[ 2 ]) = 1 then begin
768 res[ 2 ] := StringReplace( res[ 2 ], '</font>
\93\8a\8de
\93ú
\81F', '', [] );
769 end else if AnsiPos('
\93\8a\8de
\93ú
\81F', res[ 2 ]) = 1 then begin
770 res[ 2 ] := StringReplace( res[ 2 ], '
\93\8a\8de
\93ú
\81F', '', [] );
773 ioHTML[ i ] := CustomStringReplace( res.Text, #13#10, '<>');
774 //StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
782 // *************************************************************************
784 // *************************************************************************
785 procedure TMachiBBSThreadItem.LoadDat;
788 if FDat = nil then begin
789 if IsLogFile then begin
790 // dat
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
791 FDat := TStringList.Create;
792 FDat.LoadFromFile( FilePath );
798 // *************************************************************************
800 // *************************************************************************
801 procedure TMachiBBSThreadItem.FreeDat;
804 if FDat <> nil then begin
811 // *************************************************************************
812 //
\88À
\91S
\82È( '/'
\82Å
\8fI
\82í
\82é )
\93Ç
\82Ý
\8d\9e\82Ý
\82Ì URL
813 // *************************************************************************
814 function TMachiBBSThreadItem.ReadURL : string;
817 uriList : TStringList;
821 foundPos := AnsiPos( '?', URL );
822 if foundPos > 0 then begin
823 uri := TIdURI.Create( URL );
824 uriList := TStringList.Create;
826 ExtractHttpFields( ['&'], [], Copy( URL, foundPos + 1, MaxInt ), uriList );
828 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
829 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ];
838 // *************************************************************************
839 // TThreadItem
\82ª
\90¶
\90¬
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSThreadItem
\82ð
\90¶
\90¬
\82·
\82é)
840 // *************************************************************************
841 procedure ThreadItemOnCreateOfTMachiBBSThreadItem(
845 threadItem : TMachiBBSThreadItem;
848 threadItem := TMachiBBSThreadItem.Create( inInstance );
849 ThreadItemSetLong( inInstance, tipContext, DWORD( threadItem ) );
853 // *************************************************************************
854 // TThreadItem
\82ª
\94j
\8aü
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSThreadItem
\82ð
\94j
\8aü
\82·
\82é)
855 // *************************************************************************
856 procedure ThreadItemOnDisposeOfTMachiBBSThreadItem(
860 threadItem : TMachiBBSThreadItem;
863 threadItem := TMachiBBSThreadItem( ThreadItemGetLong( inInstance, tipContext ) );
868 // =========================================================================
869 // TMachiBBSBoardItem
870 // =========================================================================
872 // *************************************************************************
873 //
\83R
\83\93\83X
\83g
\83\89\83N
\83^
874 // *************************************************************************
875 constructor TMachiBBSBoardItem.Create(
880 uriList : TStringList;
885 OnDownload := Download;
886 OnCreateThread := CreateThread;
887 OnEnumThread := EnumThread;
888 OnFileName2ThreadURL := ToThreadURL;
891 FIsTemporary := False;
894 uri := TIdURI.Create( SubjectURL );
895 uriList := TStringList.Create;
897 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
898 // http://hokkaido.machi.to/hokkaidou/subject.txt
899 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
900 IsLogFile := FileExists( FilePath );
908 // *************************************************************************
909 //
\83f
\83X
\83g
\83\89\83N
\83^
910 // *************************************************************************
911 destructor TMachiBBSBoardItem.Destroy;
914 if FDat <> nil then begin
922 //
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82Ì
\8fê
\8d\87\82Í
\8dí
\8f\9c\82·
\82é
924 DeleteFile( FilePath );
930 // *************************************************************************
931 //
\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½
932 // *************************************************************************
933 function TMachiBBSBoardItem.Download : TDownloadState;
937 responseCode : Longint;
939 uriList : TStringList;
944 if FDat <> nil then begin
951 FDat := TStringList.Create;
952 uri := TIdURI.Create( SubjectURL );
953 uriList := TStringList.Create;
954 //
\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Í
955 // InternalDownload
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
956 modified := LastModified;
957 responseCode := InternalDownload( PChar( uri.URI ), modified, downResult );
959 if responseCode = 200 then begin
961 //
\83p
\83X
\82ð
\8eZ
\8fo
962 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
963 if MyLogFolder = '' then begin
964 //
\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¶
965 FilePath := TemporaryFile;
966 FIsTemporary := True;
968 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
969 FIsTemporary := False
972 //
\95Û
\91¶
\97p
\82Ì
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ð
\8c@
\82é
973 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
975 FDat.Text := string( downResult );
977 FDat.SaveToFile( FilePath );
981 LastModified := modified;
987 Result := dsComplete;
990 DisposeResultString( downResult );
995 // *************************************************************************
996 //
\83X
\83\8c\97§
\82Ä
\82ð
\8ew
\8e¦
\82³
\82ê
\82½
997 // *************************************************************************
998 function TMachiBBSBoardItem.CreateThread(
999 inSubject : string; //
\83X
\83\8c\83^
\83C
1000 inName : string; //
\96¼
\91O(
\83n
\83\93\83h
\83\8b)
1001 inMail : string; //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
1002 inMessage : string //
\96{
\95¶
1003 ) : TDownloadState; //
\8f\91\82«
\8d\9e\82Ý
\82ª
\90¬
\8c÷
\82µ
\82½
\82©
\82Ç
\82¤
\82©
1009 uriList : TStringList;
1012 uri := TIdURI.Create( URL );
1013 uriList := TStringList.Create;
1017 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
1019 postURL := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
1021 'SUBJECT=' + HttpEncode( inSubject ) +
1022 '&NAME=' + HttpEncode( inName ) +
1023 '&MAIL=' + HttpEncode( inMail ) +
1024 '&MESSAGE=' + HttpEncode( inMessage ) +
1025 '&BBS=' + uriList[ 1 ] +
1026 '&TIME=' + IntToStr( DateTimeToUnix( Now ) ) +
1027 '&submit=' + HttpEncode( '
\90V
\8bK
\8f\91\82«
\8d\9e\82Ý' );
1029 //
\93Æ
\8e©
\82É
\92Ê
\90M
\82µ
\82È
\82¢
\8fê
\8d\87\82Í InternalPost
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
1030 InternalPost( PChar( postURL ), PChar( postData ), postResult );
1031 DisposeResultString( postResult );
1033 Result := dsComplete
1041 // *************************************************************************
1042 //
\83X
\83\8c\88ê
\97\97\82Ì URL
\82©
\82ç
\83X
\83\8c\83b
\83h
\82Ì URL
\82ð
\93±
\82«
\8fo
\82·
1043 // *************************************************************************
1044 function TMachiBBSBoardItem.ToThreadURL(
1045 inFileName : string //
\83X
\83\8c\83b
\83h
\83t
\83@
\83C
\83\8b\96¼
1046 ) : string; //
\83X
\83\8c\83b
\83h
\82Ì URL
1050 uriList : TStringList;
1054 found := AnsiPos( '.', inFileName );
1056 inFileName := Copy( inFileName, 1, found - 1 );
1058 uri := TIdURI.Create( SubjectURL );
1059 uriList := TStringList.Create;
1062 // http://hokkaido.machi.to/hokkaidou/
1063 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
1064 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
1065 threadURL := uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
1066 'BBS=' + uriList[ 1 ] + '&KEY=' + inFileName + '&LAST=50';
1067 Result := threadURL;
1078 // *************************************************************************
1079 //
\82±
\82Ì
\94Â
\82É
\82¢
\82
\82Â
\82Ì
\83X
\83\8c\82ª
\82 \82é
\82©
\97v
\8b\81\82³
\82ê
\82½
1080 // *************************************************************************
1081 procedure TMachiBBSBoardItem.EnumThread(
1082 inCallBack : TBoardItemEnumThreadCallBack
1086 uriList : TStringList;
1090 if FDat = nil then begin
1091 FDat := TStringList.Create;
1093 uri := TIdURI.Create( SubjectURL );
1094 uriList := TStringList.Create;
1096 //
\83p
\83X
\82ð
\8eZ
\8fo
1097 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
1098 // http://hokkaido.machi.to/hokkaidou/subject.txt
1099 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
1100 if FileExists( FilePath ) then
1101 //
\93Ç
\82Ý
\8d\9e\82Ý
1102 FDat.LoadFromFile( FilePath );
1109 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í EnumThread
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
1110 inherited EnumThread( inCallBack, CustomStringReplace( FDat.Text, ',', '<>' ) );
1116 // *************************************************************************
1117 //
\83X
\83\8c\88ê
\97\97\82Ì URL
\82ð
\8b\81\82ß
\82é
1118 // *************************************************************************
1119 function TMachiBBSBoardItem.SubjectURL : string;
1122 uriList : TStringList;
1125 uri := TIdURI.Create( URL );
1126 uriList := TStringList.Create;
1128 if uri.Document <> SUBJECT_NAME then begin
1129 if Copy( URL, Length( URL ), 1 ) = '/' then
1130 Result := URL + SUBJECT_NAME
1132 Result := URL + '/' + SUBJECT_NAME;
1134 //
\82±
\82±
\82É
\82Í
\97\88\82È
\82¢
\82Æ
\8ev
\82¤
\82¯
\82Ç
1144 // *************************************************************************
1145 // TBoardItem
\82ª
\90¶
\90¬
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSBoardItem
\82ð
\90¶
\90¬
\82·
\82é)
1146 // *************************************************************************
1147 procedure BoardItemOnCreateOfTMachiBBSBoardItem(
1151 boardItem : TMachiBBSBoardItem;
1154 boardItem := TMachiBBSBoardItem.Create( inInstance );
1155 BoardItemSetLong( inInstance, bipContext, DWORD( boardItem ) );
1159 // *************************************************************************
1160 // TBoardItem
\82ª
\94j
\8aü
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSBoardItem
\82ð
\94j
\8aü
\82·
\82é)
1161 // *************************************************************************
1162 procedure BoardItemOnDisposeOfTMachiBBSBoardItem(
1166 boardItem : TMachiBBSBoardItem;
1169 boardItem := TMachiBBSBoardItem( BoardItemGetLong( inInstance, bipContext ) );
1176 // =========================================================================
1177 //
\83G
\83\93\83g
\83\8a\83|
\83C
\83\93\83g
1178 // =========================================================================
1180 ul_reason_for_call : DWORD
1186 case ul_reason_for_call of
1191 module := GetModuleHandle( nil );
1193 LoadInternalAPI( module );
1194 LoadInternalFilePathAPI( module );
1195 LoadInternalThreadItemAPI( module );
1196 LoadInternalBoardItemAPI( module );
1198 // =====
\83C
\83\93\83X
\83^
\83\93\83X
\82Ì
\8eæ
\82è
\88µ
\82¢
\82ð TThreadItem
\82©
\82ç TMachiBBSThreadItem
\82É
\95Ï
\8dX
\82·
\82é
1199 ThreadItemOnCreate := ThreadItemOnCreateOfTMachiBBSThreadItem;
1200 ThreadItemOnDispose := ThreadItemOnDisposeOfTMachiBBSThreadItem;
1201 // =====
\83C
\83\93\83X
\83^
\83\93\83X
\82Ì
\8eæ
\82è
\88µ
\82¢
\82ð TBoardItem
\82©
\82ç TMachiBBSBoardItem
\82É
\95Ï
\8dX
\82·
\82é
1202 BoardItemOnCreate := BoardItemOnCreateOfTMachiBBSBoardItem;
1203 BoardItemOnDispose := BoardItemOnDisposeOfTMachiBBSBoardItem;
1222 DllProc := @DLLEntry;
1223 DLLEntry( DLL_PROCESS_ATTACH );