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;
45 //property FilePath : string read FFilePath;
48 // =========================================================================
50 // =========================================================================
51 TMachiBBSBoardItem = class(TBoardItem)
53 FIsTemporary : Boolean;
57 constructor Create( inInstance : DWORD );
58 destructor Destroy; override;
61 function Download : TDownloadState;
62 function CreateThread( inSubject : string; inName : string; inMail : string; inMessage : string ) : TDownloadState;
63 function ToThreadURL( inFileName : string ) : string;
64 procedure EnumThread( inCallBack : TBoardItemEnumThreadCallBack );
66 function SubjectURL : string;
69 // =========================================================================
70 //
\83T
\83u
\83W
\83F
\83N
\83g
\83\8c\83R
\81[
\83h
71 // =========================================================================
79 LOG_DIR = 'MachiBBS\';
80 SUBJECT_NAME = 'subject.txt';
82 PLUGIN_NAME = 'MachiBBSPlugIn';
85 RELEASE_VERSION = 'beta';
86 REVISION_VERSION = 17;
88 // =========================================================================
90 // =========================================================================
92 // *************************************************************************
93 //
\83e
\83\93\83|
\83\89\83\8a\82È
\83p
\83X
\82Ì
\8eæ
\93¾
94 // *************************************************************************
95 function TemporaryFile : string;
97 tempPath : array [0..MAX_PATH] of char;
100 GetTempPath( SizeOf(tempPath), tempPath );
102 Result := tempPath + IntToStr( Random( $7fffffff ) );
103 until not FileExists( Result );
107 // *************************************************************************
108 //
\82Ü
\82¿BBS
\97p
\83\8d\83O
\83t
\83H
\83\8b\83_
\8eæ
\93¾
109 // *************************************************************************
110 function MyLogFolder : string;
116 if Length( folder ) = 0 then
119 Result := folder + LOG_DIR;
120 DisposeResultString(folder);
124 (*************************************************************************
125 *
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ª
\91¶
\8dÝ
\82·
\82é
\82©
\83`
\83F
\83b
\83N
126 *************************************************************************)
127 function DirectoryExistsEx(const Name: string): Boolean;
131 Code := GetFileAttributes(PChar(Name));
132 Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
135 (*************************************************************************
136 *
\83f
\83B
\83\8c\83N
\83g
\83\8a\8dì
\90¬
\81i
\95¡
\90\94\8aK
\91w
\91Î
\89\9e\81j
137 *************************************************************************)
138 function ForceDirectoriesEx(Dir: string): Boolean;
141 if Length(Dir) = 0 then
142 raise Exception.Create('
\83t
\83H
\83\8b\83_
\82ª
\8dì
\90¬
\8fo
\97\88\82Ü
\82¹
\82ñ');
143 Dir := ExcludeTrailingPathDelimiter(Dir);
144 if (Length(Dir) < 3) or DirectoryExistsEx(Dir)
145 or (ExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
146 Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
149 //
\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
150 procedure ExtractHttpFields(
151 const chrSep : TSysCharSet;
152 const chrWhite : TSysCharSet;
153 const strValue : string;
154 var strResult : TStringList;
155 unknownFlag : boolean = false
158 last, p, strLen : Integer;
161 strLen := Length( strValue );
168 if strValue[ p ] in chrSep then
170 strResult.Add( Copy( strValue, last, p - last ) );
179 strResult.Add( Copy( strValue, last, strLen - last + 1 ) );
183 \rfunction HttpEncode(
184 \r const strValue : string
192 kHexCode : array [0..15] of char = (
193 '0', '1', '2', '3', '4', '5', '6', '7',
194 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' );
197 strLen := Length( strValue );
203 case strValue[ i ] of
204 '0' .. '9', 'a' .. 'z', 'A' .. 'Z', '*', '-', '.', '@', '_':
206 strResult := strResult + strValue[ i ];
210 b := Integer( strValue[ i ] );
211 strResult := strResult + '%'
212 + kHexCode[ b div $10 ]
213 + kHexCode[ b mod $10 ];
227 // =========================================================================
229 // =========================================================================
231 // *************************************************************************
232 //
\83v
\83\89\83O
\83C
\83\93\82Ì
\83o
\81[
\83W
\83\87\83\93\82ð
\97v
\8b\81\82³
\82ê
\82½
233 // *************************************************************************
234 procedure OnVersionInfo(
235 var outAgent : PChar; //
\83o
\81[
\83W
\83\87\83\93\82ð
\88ê
\90Ø
\8aÜ
\82Ü
\82È
\82¢
\8f\83\90\88\82È
\96¼
\8fÌ
236 var outMajor : DWORD; //
\83\81\83W
\83\83\81[
\83o
\81[
\83W
\83\87\83\93
237 var outMinor : DWORD; //
\83}
\83C
\83i
\81[
\83o
\81[
\83W
\83\87\83\93
238 var outRelease : PChar; //
\83\8a\83\8a\81[
\83X
\92i
\8aK
\96¼
239 var outRevision : DWORD //
\83\8a\83r
\83W
\83\87\83\93\83i
\83\93\83o
\81[
244 outAgent := CreateResultString( PChar( PLUGIN_NAME ) );
245 outMajor := MAJOR_VERSION;
246 outMinor := MINOR_VERSION;
247 outRelease := CreateResultString( PChar( RELEASE_VERSION ) );
248 outRevision := REVISION_VERSION;
259 // *************************************************************************
260 //
\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©
261 // *************************************************************************
262 function OnAcceptURL(
263 inURL : PChar //
\94»
\92f
\82ð
\8bÂ
\82¢
\82Å
\82¢
\82é URL
264 ): TAcceptType; stdcall; // URL
\82Ì
\8eí
\97Þ
267 uriList : TStringList;
270 BBS_HOST = 'machi.to';
271 THREAD_MARK = '/bbs/read.pl';
275 //
\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 );
277 uriList := TStringList.Create;
279 ExtractHttpFields( ['/'], [], uri.Path, uriList );
280 foundPos := AnsiPos( BBS_HOST, uri.Host );
281 if (foundPos > 0) and (Length( uri.Host ) - foundPos + 1 = Length( BBS_HOST )) then begin
282 foundPos := Pos( THREAD_MARK, inURL );
285 else if (uriList.Count > 1) and (uri.Path <> '/') then //
\8dÅ
\8cã
\82ª '/'
\82Å
\95Â
\82ß
\82ç
\82ê
\82Ä
\82é
\82È
\82ç 3
290 Result := atNoAccept;
297 Result := atNoAccept;
302 // *************************************************************************
303 //
\8ew
\92è
\82µ
\82½ URL
\82ðBoard
\82ÌURL
\82É
\95Ï
\8a·
304 // *************************************************************************
305 procedure OnExtractBoardURL(
311 uriList : TStringList;
314 THREAD_MARK = '/bbs/read.pl';
316 URL := string(inURL);
317 if AnsiPos(THREAD_MARK, URL) > 0 then begin
318 if Copy( inURL, Length( inURL ), 1 ) = '/' then
319 uri := TIdURI.Create( URL )
321 uri := TIdURI.Create( URL + '/' );
323 uriList := TStringList.Create;
327 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ),uriList );
328 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
329 // http://hokkaido.machi.to/hokkaidou/
330 URL := uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/';
331 outURL := CreateResultString(URL);
337 outURL := CreateResultString(URL);
343 // =========================================================================
344 // TMachiBBSThreadItem
345 // =========================================================================
347 // *************************************************************************
348 //
\83R
\83\93\83X
\83g
\83\89\83N
\83^
349 // *************************************************************************
350 constructor TMachiBBSThreadItem.Create(
355 uriList : TStringList;
361 OnDownload := Download;
365 OnGetHeader := GetHeader;
366 OnGetFooter := GetFooter;
367 OnGetBoardURL := GetBoardURL;
370 FIsTemporary := False;
372 URL := ReadURL + '&LAST=50';
374 uri := TIdURI.Create( URL );
375 uriList := TStringList.Create;
377 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
380 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
381 FileName := uriList.Values[ 'KEY' ] + '.dat';
382 FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
383 IsLogFile := FileExists( FilePath );
391 // *************************************************************************
392 //
\83f
\83X
\83g
\83\89\83N
\83^
393 // *************************************************************************
394 destructor TMachiBBSThreadItem.Destroy;
399 //
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82Ì
\8fê
\8d\87\82Í
\8dí
\8f\9c\82·
\82é
401 DeleteFile( FilePath );
407 // *************************************************************************
408 //
\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½
409 // *************************************************************************
410 function TMachiBBSThreadItem.Download : TDownloadState;
414 downResult : TStringList;
415 content : TStringList;
416 responseCode : Longint;
417 logStream : TFileStream;
419 uriList : TStringList;
423 procedure downAndParse;
425 responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
428 if responseCode = 200 then begin
429 downResult := TStringList.Create;
431 downResult.Text := string( tmp );
433 //
\83^
\83C
\83g
\83\8b\82Ì
\8eæ
\93¾
434 foundPos := AnsiPos( '<title>', downResult.Text ) + Length( '<title>' );
438 AnsiPos( '</title>', downResult.Text ) - foundPos );
440 //
\83\8c\83X
\82Ì
\8aJ
\8en
\88Ê
\92u
441 foundPos := AnsiPos( '<dt', downResult.Text );
442 downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
443 if foundPos > 0 then begin
444 //
\83\8c\83X
\82Ì
\8fI
\97¹
\88Ê
\92u
445 foundPos := AnsiPos( '<table', downResult.Text ) - 1;
447 downResult.Text := Copy( downResult.Text, 1, foundPos );
449 //
\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Å
450 //
\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¤
451 To2chDat( downResult, Count + 1 );
452 content.Text := content.Text + downResult.Text;
458 Result := dsNotModify;
462 DisposeResultString( tmp );
469 uri := TIdURI.Create( URL );
470 uriList := TStringList.Create;
471 content := TStringList.Create;
475 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
476 FileName := uriList.Values[ 'KEY' ] + '.dat';
477 if MyLogFolder = '' then begin
478 //
\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¶
479 FilePath := TemporaryFile;
480 FIsTemporary := True;
482 FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
483 FIsTemporary := False;
486 //
\95Û
\91¶
\97p
\82Ì
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ð
\8c@
\82é
487 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
489 //
\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Í
490 // InternalDownload
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
491 modified := LastModified;
495 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
496 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
497 '&START=' + IntToStr( 1 )
499 //
\90V
\92\85\82Ì
\82Ý
501 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
502 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
503 '&START=' + IntToStr( Count + 1 ) + '&NOFIRST=TRUE';
504 //
\83_
\83E
\83\93\83\8d\81[
\83h
507 if content.Count > 0 then begin
508 if Count <= 0 then begin
509 Result := dsComplete;
510 //
\90V
\8bK
\8f\91\82«
\8d\9e\82Ý
511 content[ 0 ] := content[ 0 ] + Title;
512 logStream := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
514 logStream.Position := logStream.Size;
515 logStream.Write( PChar( content.Text )^, Length( content.Text ) );
520 Count := content.Count;
522 Result := dsDiffComplete;
524 logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite );
526 logStream.Position := logStream.Size;
527 logStream.Write( PChar( content.Text )^, Length( content.Text ) );
531 NewReceive := Count + 1;
532 Count := Count + content.Count;
535 // CGI
\82©
\82ç
\82Í
\90³
\82µ
\82¢
\93ú
\95t
\82ª
\93¾
\82ç
\82ê
\82È
\82¢
\82Ì
\82Å
\8c»
\8dÝ
\82É
\90Ý
\92è
537 NewResCount := content.Count;
539 Result := dsNotModify;
549 // *************************************************************************
550 //
\8f\91\82«
\8d\9e\82Ý
\82ð
\8ew
\8e¦
\82³
\82ê
\82½
551 // *************************************************************************
552 function TMachiBBSThreadItem.Write(
553 inName : string; //
\96¼
\91O(
\83n
\83\93\83h
\83\8b)
554 inMail : string; //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
555 inMessage : string //
\96{
\95¶
556 ) : TDownloadState; //
\8f\91\82«
\8d\9e\82Ý
\82ª
\90¬
\8c÷
\82µ
\82½
\82©
\82Ç
\82¤
\82©
562 uriList : TStringList;
565 uri := TIdURI.Create( URL );
566 uriList := TStringList.Create;
570 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
572 postURL := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
574 'NAME=' + HttpEncode( inName ) +
575 '&MAIL=' + HttpEncode( inMail ) +
576 '&MESSAGE=' + HttpEncode( inMessage ) +
577 '&BBS=' + uriList.Values[ 'BBS' ] +
578 '&KEY=' + uriList.Values[ 'KEY' ] +
579 '&TIME=' + IntToStr( DateTimeToUnix( Now ) ) +
580 '&submit=' + HttpEncode( '
\8f\91\82«
\8d\9e\82Þ' );
582 //
\93Æ
\8e©
\82É
\92Ê
\90M
\82µ
\82È
\82¢
\8fê
\8d\87\82Í InternalPost
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
583 InternalPost( PChar( postURL ), PChar( postData ),PChar(URL), postResult );
584 DisposeResultString( postResult );
594 // *************************************************************************
595 //
\83\8c\83X
\94Ô
\8d\86 inNo
\82É
\91Î
\82·
\82é html
\82ð
\97v
\8b\81\82³
\82ê
\82½
596 // *************************************************************************
597 function TMachiBBSThreadItem.GetRes(
598 inNo : Integer //
\97v
\8b\81\82³
\82ê
\82½
\83\8c\83X
\94Ô
\8d\86
599 ) : string; //
\91Î
\89\9e\82·
\82é HTML
605 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
606 // InternalAbon
\82¨
\82æ
\82Ñ Dat2HTML
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
608 if (FDat = nil) or (inNo - 1 < 0 ) or (inNo - 1 >= FDat.Count) then begin
609 //
\83\8d\83O
\82É
\91¶
\8dÝ
\82µ
\82È
\82¢
\82Ì
\82Å
\82±
\82Ì
\82Ü
\82Ü
\8fI
\97¹
613 res := FDat[ inNo - 1 ];
614 tmp := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
616 Result := Dat2HTML( string( tmp ), inNo );
618 DisposeResultString( tmp );
623 // *************************************************************************
624 //
\83\8c\83X
\94Ô
\8d\86 inNo
\82É
\91Î
\82·
\82é Dat
\82ð
\97v
\8b\81\82³
\82ê
\82½
625 // *************************************************************************
626 function TMachiBBSThreadItem.GetDat(
627 inNo : Integer //
\97v
\8b\81\82³
\82ê
\82½
\83\8c\83X
\94Ô
\8d\86
628 ) : string; //
\82Q
\82¿
\82á
\82ñ
\82Ë
\82é
\82ÌDat
\8c`
\8e®
634 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
636 if (FDat = nil) or (inNo - 1 < 0 ) or (inNo - 1 >= FDat.Count) then begin
637 //
\83\8d\83O
\82É
\91¶
\8dÝ
\82µ
\82È
\82¢
\82Ì
\82Å
\82±
\82Ì
\82Ü
\82Ü
\8fI
\97¹
638 tmp := CreateResultString('');
640 DisposeResultString(tmp);
643 tmp := CreateResultString(FDat[ inNo - 1]);
645 Result := string(tmp);
647 DisposeResultString(tmp);
652 // *************************************************************************
653 //
\83X
\83\8c\83b
\83h
\82Ì
\83w
\83b
\83_ html
\82ð
\97v
\8b\81\82³
\82ê
\82½
654 // *************************************************************************
655 function TMachiBBSThreadItem.GetHeader(
656 inOptionalHeader : string
660 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
661 // InternalHeader
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
662 Result := InternalHeader(
663 '<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">' +
667 // GetRes
\82ð
\8cÄ
\82Î
\82ê
\82é
\82±
\82Æ
\82ª
\97\
\91z
\82³
\82ê
\82é
\82Ì
\82Å FDat
\82ð
\90¶
\90¬
\82µ
\82Ä
\82¨
\82
676 // *************************************************************************
677 //
\83X
\83\8c\83b
\83h
\82Ì
\83t
\83b
\83^ html
\82ð
\97v
\8b\81\82³
\82ê
\82½
678 // *************************************************************************
679 function TMachiBBSThreadItem.GetFooter(
680 inOptionalFooter : string
684 //
\93Æ
\8e©
\82É
\83t
\83B
\83\8b\83^
\83\8a\83\93\83O
\82ð
\8ds
\82í
\82È
\82¢
\8fê
\8d\87\82Í
685 // InternalFooter
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
686 Result := InternalFooter( inOptionalFooter );
688 //
\82à
\82¤ GetRes
\82Í
\8cÄ
\82Î
\82ê
\82È
\82¢
\82Æ
\8ev
\82¤
\82Ì
\82Å FDat
\82ð
\8aJ
\95ú
\82µ
\82Ä
\82¨
\82
696 // *************************************************************************
697 //
\82±
\82Ì ThreadItem
\82ª
\91®
\82·
\82é
\94Â
\82Ì URL
\82ð
\97v
\8b\81\82³
\82ê
\82½
698 // *************************************************************************
699 function TMachiBBSThreadItem.GetBoardURL : string;
702 uriList : TStringList;
706 if Copy( URL, Length( URL ), 1 ) = '/' then
707 uri := TIdURI.Create( URL )
709 uri := TIdURI.Create( URL + '/' );
710 uriList := TStringList.Create;
714 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
715 FileName := uriList.Values[ 'KEY' ] + '.dat';
716 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
717 // http://hokkaido.machi.to/hokkaidou/
718 tmp := CreateResultString(
719 uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/' );
720 Result := string(tmp);
722 DisposeResultString(tmp);
729 // *************************************************************************
730 //
\82Ü
\82¿BBS
\82Ì HTML
\82ð 2ch
\82Ì dat
\8c`
\8e®
\82É
731 // *************************************************************************
732 procedure TMachiBBSThreadItem.To2chDat(
733 ioHTML : TStringList;
734 inStartNo : Integer = 1
743 MAIL_TAG = '<a href="mailto:';
746 //===== 2ch
\82Ì dat
\8c`
\8e®
\82É
\95Ï
\8a·
747 //
\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
748 ioHTML.Text := CustomStringReplace( ioHTML.Text, #13#10, '');
749 //StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
750 //
\91ã
\82í
\82è
\82É <dt>
\82ð
\8ds
\82Ì
\8bæ
\90Ø
\82è
\82É
\82·
\82é
751 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<dt>', #10 );
752 //StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
753 // <dt>
\82©
\82ç
\8en
\82Ü
\82Á
\82Ä
\82¢
\82é
\82Ì
\82Å
\8dÅ
\8f\89\82Í
\8bó
\82Ì
\82Í
\82¸
754 if Length( ioHTML[ 0 ] ) = 0 then
757 //
\8cy
\82
\82 \82Ú
\81[
\82ñ
\83`
\83F
\83b
\83N
758 //
\81¦
\91å
\8eG
\94c
\82¾
\82©
\82ç
\82¿
\82á
\82ñ
\82Æ
\8fo
\97\88\82Ä
\82È
\82¢
\82©
\82à
761 while i < ioHTML.Count do begin
762 foundPos := AnsiPos( ' ', ioHTML[ i ] );
763 if foundPos > 0 then begin
764 no := StrToInt( Copy( ioHTML[ i ], 1, foundPos - 1 ) );
765 if inStartNo < no then
766 ioHTML.Insert( i, '<><><><>' );
772 //
\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Å
775 //
\83g
\83\8a\83b
\83v
\82Ì
\8cã
\82Ì '<b> </b>'
\82ð
\8bó
\82É
776 if AnsiPos('
\81\9f</b>', ioHTML.Text) <> 0 then begin
777 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </b></font>', '</b></font>', true );
778 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </B></a>', '</b></a>', true );
780 //ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </b>', '', true );
781 //StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
782 // '<b>'
\82Í
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82Ì
\8bæ
\90Ø
\82è
783 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b>', '<>', true );
784 //StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
785 //
\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É
786 ioHTML.Text := CustomStringReplace( ioHTML.Text, '</b></a>', '<>', true );
787 //StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
788 ioHTML.Text := CustomStringReplace( ioHTML.Text, '</b>', '<>', true );
789 ioHTML.Text := CustomStringReplace( ioHTML.Text, '
\81\9f<>', '
\81\9f</b>', true );
790 //StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
791 // '<dd>'
\82ð
\96{
\95¶
\82Æ
\82Ì
\8bæ
\90Ø
\82è
\82É
792 ioHTML.Text := CustomStringReplace( ioHTML.Text, '<dd>', '<>', true );
793 //StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
795 res := TStringList.Create;
797 bound := ioHTML.Count - 1;
798 for i := 0 to bound do begin
799 res.Text := CustomStringReplace( ioHTML[ i ], '<>', #10 );
800 //StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
801 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ß
802 foundPos := AnsiPos( MAIL_TAG, res[ 0 ] );
803 if foundPos > 0 then begin
804 //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
\82ð
\94²
\82«
\8fo
\82·
805 foundPos := foundPos + Length( MAIL_TAG );
806 res[ 0 ] := Copy( res[ 0 ], foundPos, Length( res[ 0 ] ) );
807 strTmp := Copy( res[ 0 ], 1, AnsiPos( '">', res[ 0 ] ) - 1 );
808 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82ª
\8bt
\82È
\82Ì
\82Å
\82Ð
\82Á
\82
\82è
\95Ô
\82µ
\82Ä
\96ß
\82·
809 res[ 0 ] := res[ 1 ];
812 //
\83\81\81[
\83\8b\82Æ
\96¼
\91O
\82ª
\8bt
\82È
\82Ì
\82Å
\82Ð
\82Á
\82
\82è
\95Ô
\82·
813 res[ 0 ] := res[ 1 ];
816 res[ 2 ] := StringReplace( res[ 2 ], '[', 'IP:', [] );
817 res[ 2 ] := StringReplace( res[ 2 ], ']', '', [] );
819 if AnsiPos('</font>
\93\8a\8de
\93ú
\81F', res[ 2 ]) = 1 then begin
820 res[ 2 ] := StringReplace( res[ 2 ], '</font>
\93\8a\8de
\93ú
\81F', '', [] );
821 end else if AnsiPos('
\93\8a\8de
\93ú
\81F', res[ 2 ]) = 1 then begin
822 res[ 2 ] := StringReplace( res[ 2 ], '
\93\8a\8de
\93ú
\81F', '', [] );
825 ioHTML[ i ] := CustomStringReplace( res.Text, #13#10, '<>');
826 //StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
834 // *************************************************************************
836 // *************************************************************************
837 procedure TMachiBBSThreadItem.LoadDat;
840 if FDat = nil then begin
841 if IsLogFile then begin
842 // dat
\82Ì
\93Ç
\82Ý
\8d\9e\82Ý
843 FDat := TStringList.Create;
844 FDat.LoadFromFile( FilePath );
850 // *************************************************************************
852 // *************************************************************************
853 procedure TMachiBBSThreadItem.FreeDat;
856 if FDat <> nil then begin
863 // *************************************************************************
864 //
\88À
\91S
\82È( '/'
\82Å
\8fI
\82í
\82é )
\93Ç
\82Ý
\8d\9e\82Ý
\82Ì URL
865 // *************************************************************************
866 function TMachiBBSThreadItem.ReadURL : string;
869 uriList : TStringList;
873 foundPos := AnsiPos( '?', URL );
874 if foundPos > 0 then begin
875 uri := TIdURI.Create( URL );
876 uriList := TStringList.Create;
878 ExtractHttpFields( ['&'], [], Copy( URL, foundPos + 1, MaxInt ), uriList );
880 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
881 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ];
890 // *************************************************************************
891 // TThreadItem
\82ª
\90¶
\90¬
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSThreadItem
\82ð
\90¶
\90¬
\82·
\82é)
892 // *************************************************************************
893 procedure ThreadItemOnCreateOfTMachiBBSThreadItem(
897 threadItem : TMachiBBSThreadItem;
900 threadItem := TMachiBBSThreadItem.Create( inInstance );
901 ThreadItemSetLong( inInstance, tipContext, DWORD( threadItem ) );
905 // *************************************************************************
906 // TThreadItem
\82ª
\94j
\8aü
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSThreadItem
\82ð
\94j
\8aü
\82·
\82é)
907 // *************************************************************************
908 procedure ThreadItemOnDisposeOfTMachiBBSThreadItem(
912 threadItem : TMachiBBSThreadItem;
915 threadItem := TMachiBBSThreadItem( ThreadItemGetLong( inInstance, tipContext ) );
920 // =========================================================================
921 // TMachiBBSBoardItem
922 // =========================================================================
924 // *************************************************************************
925 //
\83R
\83\93\83X
\83g
\83\89\83N
\83^
926 // *************************************************************************
927 constructor TMachiBBSBoardItem.Create(
932 uriList : TStringList;
937 OnDownload := Download;
938 OnCreateThread := CreateThread;
939 OnEnumThread := EnumThread;
940 OnFileName2ThreadURL := ToThreadURL;
943 FIsTemporary := False;
947 uri := TIdURI.Create( SubjectURL );
948 uriList := TStringList.Create;
950 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
951 // http://hokkaido.machi.to/hokkaidou/subject.txt
952 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
953 IsLogFile := FileExists( FilePath );
961 // *************************************************************************
962 //
\83f
\83X
\83g
\83\89\83N
\83^
963 // *************************************************************************
964 destructor TMachiBBSBoardItem.Destroy;
967 if FDat <> nil then begin
975 //
\88ê
\8e\9e\83t
\83@
\83C
\83\8b\82Ì
\8fê
\8d\87\82Í
\8dí
\8f\9c\82·
\82é
977 DeleteFile( FilePath );
983 // *************************************************************************
984 //
\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½
985 // *************************************************************************
986 function TMachiBBSBoardItem.Download : TDownloadState;
990 responseCode : Longint;
992 uriList : TStringList;
997 if FDat <> nil then begin
1004 FDat := TStringList.Create;
1005 uri := TIdURI.Create( SubjectURL );
1006 uriList := TStringList.Create;
1007 //
\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Í
1008 // InternalDownload
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
1009 modified := LastModified;
1010 responseCode := InternalDownload( PChar( uri.URI ), modified, downResult );
1012 if responseCode = 200 then begin
1014 //
\83p
\83X
\82ð
\8eZ
\8fo
1015 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
1016 if MyLogFolder = '' then begin
1017 //
\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¶
1018 FilePath := TemporaryFile;
1019 FIsTemporary := True;
1021 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
1022 FIsTemporary := False
1025 //
\95Û
\91¶
\97p
\82Ì
\83f
\83B
\83\8c\83N
\83g
\83\8a\82ð
\8c@
\82é
1026 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
1028 FDat.Text := string( downResult );
1030 FDat.SaveToFile( FilePath );
1034 LastModified := modified;
1040 Result := dsComplete;
1043 DisposeResultString( downResult );
1048 // *************************************************************************
1049 //
\83X
\83\8c\97§
\82Ä
\82ð
\8ew
\8e¦
\82³
\82ê
\82½
1050 // *************************************************************************
1051 function TMachiBBSBoardItem.CreateThread(
1052 inSubject : string; //
\83X
\83\8c\83^
\83C
1053 inName : string; //
\96¼
\91O(
\83n
\83\93\83h
\83\8b)
1054 inMail : string; //
\83\81\81[
\83\8b\83A
\83h
\83\8c\83X
1055 inMessage : string //
\96{
\95¶
1056 ) : TDownloadState; //
\8f\91\82«
\8d\9e\82Ý
\82ª
\90¬
\8c÷
\82µ
\82½
\82©
\82Ç
\82¤
\82©
1062 uriList : TStringList;
1065 uri := TIdURI.Create( URL );
1066 uriList := TStringList.Create;
1070 Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
1072 postURL := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
1074 'SUBJECT=' + HttpEncode( inSubject ) +
1075 '&NAME=' + HttpEncode( inName ) +
1076 '&MAIL=' + HttpEncode( inMail ) +
1077 '&MESSAGE=' + HttpEncode( inMessage ) +
1078 '&BBS=' + uriList[ 1 ] +
1079 '&TIME=' + IntToStr( DateTimeToUnix( Now ) ) +
1080 '&submit=' + HttpEncode( '
\90V
\8bK
\8f\91\82«
\8d\9e\82Ý' );
1082 //
\93Æ
\8e©
\82É
\92Ê
\90M
\82µ
\82È
\82¢
\8fê
\8d\87\82Í InternalPost
\82É
\94C
\82¹
\82é
\82±
\82Æ
\82ª
\8fo
\97\88\82é
1083 InternalPost( PChar( postURL ), PChar( postData ),PChar(URL), postResult );
1084 DisposeResultString( postResult );
1086 Result := dsComplete
1094 // *************************************************************************
1095 //
\83X
\83\8c\88ê
\97\97\82Ì URL
\82©
\82ç
\83X
\83\8c\83b
\83h
\82Ì URL
\82ð
\93±
\82«
\8fo
\82·
1096 // *************************************************************************
1097 function TMachiBBSBoardItem.ToThreadURL(
1098 inFileName : string //
\83X
\83\8c\83b
\83h
\83t
\83@
\83C
\83\8b\96¼
1099 ) : string; //
\83X
\83\8c\83b
\83h
\82Ì URL
1103 uriList : TStringList;
1107 found := AnsiPos( '.', inFileName );
1109 inFileName := Copy( inFileName, 1, found - 1 );
1111 uri := TIdURI.Create( SubjectURL );
1112 uriList := TStringList.Create;
1115 // http://hokkaido.machi.to/hokkaidou/
1116 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
1117 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
1118 threadURL := uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
1119 'BBS=' + uriList[ 1 ] + '&KEY=' + inFileName + '&LAST=50';
1120 Result := threadURL;
1131 // *************************************************************************
1132 //
\82±
\82Ì
\94Â
\82É
\82¢
\82
\82Â
\82Ì
\83X
\83\8c\82ª
\82 \82é
\82©
\97v
\8b\81\82³
\82ê
\82½
1133 // *************************************************************************
1134 procedure TMachiBBSBoardItem.EnumThread(
1135 inCallBack : TBoardItemEnumThreadCallBack
1139 uriList : TStringList;
1143 if FDat = nil then begin
1144 FDat := TStringList.Create;
1146 uri := TIdURI.Create( SubjectURL );
1147 uriList := TStringList.Create;
1149 //
\83p
\83X
\82ð
\8eZ
\8fo
1150 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
1151 // http://hokkaido.machi.to/hokkaidou/subject.txt
1152 FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
1153 if FileExists( FilePath ) then
1154 //
\93Ç
\82Ý
\8d\9e\82Ý
1155 FDat.LoadFromFile( FilePath );
1162 //
\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é
1163 inherited EnumThread( inCallBack, CustomStringReplace( FDat.Text, ',', '<>' ) );
1169 // *************************************************************************
1170 //
\83X
\83\8c\88ê
\97\97\82Ì URL
\82ð
\8b\81\82ß
\82é
1171 // *************************************************************************
1172 function TMachiBBSBoardItem.SubjectURL : string;
1175 uriList : TStringList;
1178 uri := TIdURI.Create( URL );
1179 uriList := TStringList.Create;
1181 if uri.Document <> SUBJECT_NAME then begin
1182 if Copy( URL, Length( URL ), 1 ) = '/' then
1183 Result := URL + SUBJECT_NAME
1185 Result := URL + '/' + SUBJECT_NAME;
1187 //
\82±
\82±
\82É
\82Í
\97\88\82È
\82¢
\82Æ
\8ev
\82¤
\82¯
\82Ç
1197 // *************************************************************************
1198 // TBoardItem
\82ª
\90¶
\90¬
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSBoardItem
\82ð
\90¶
\90¬
\82·
\82é)
1199 // *************************************************************************
1200 procedure BoardItemOnCreateOfTMachiBBSBoardItem(
1204 boardItem : TMachiBBSBoardItem;
1207 boardItem := TMachiBBSBoardItem.Create( inInstance );
1208 BoardItemSetLong( inInstance, bipContext, DWORD( boardItem ) );
1212 // *************************************************************************
1213 // TBoardItem
\82ª
\94j
\8aü
\82³
\82ê
\82½
\8fê
\8d\87\82Ì
\8f\88\92u(TMachiBBSBoardItem
\82ð
\94j
\8aü
\82·
\82é)
1214 // *************************************************************************
1215 procedure BoardItemOnDisposeOfTMachiBBSBoardItem(
1219 boardItem : TMachiBBSBoardItem;
1222 boardItem := TMachiBBSBoardItem( BoardItemGetLong( inInstance, bipContext ) );
1229 // =========================================================================
1230 //
\83G
\83\93\83g
\83\8a\83|
\83C
\83\93\83g
1231 // =========================================================================
1233 ul_reason_for_call : DWORD
1239 case ul_reason_for_call of
1244 module := GetModuleHandle( nil );
1246 LoadInternalAPI( module );
1247 LoadInternalFilePathAPI( module );
1248 LoadInternalThreadItemAPI( module );
1249 LoadInternalBoardItemAPI( module );
1251 // =====
\83C
\83\93\83X
\83^
\83\93\83X
\82Ì
\8eæ
\82è
\88µ
\82¢
\82ð TThreadItem
\82©
\82ç TMachiBBSThreadItem
\82É
\95Ï
\8dX
\82·
\82é
1252 ThreadItemOnCreate := ThreadItemOnCreateOfTMachiBBSThreadItem;
1253 ThreadItemOnDispose := ThreadItemOnDisposeOfTMachiBBSThreadItem;
1254 // =====
\83C
\83\93\83X
\83^
\83\93\83X
\82Ì
\8eæ
\82è
\88µ
\82¢
\82ð TBoardItem
\82©
\82ç TMachiBBSBoardItem
\82É
\95Ï
\8dX
\82·
\82é
1255 BoardItemOnCreate := BoardItemOnCreateOfTMachiBBSBoardItem;
1256 BoardItemOnDispose := BoardItemOnDisposeOfTMachiBBSBoardItem;
1275 DllProc := @DLLEntry;
1276 DLLEntry( DLL_PROCESS_ATTACH );