{
MachiBBSBoardPlugIn
\82Ü\82¿BBS\8f\88\97\9d\83\86\83j\83b\83g
- \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
- \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
}
uses
- Windows,
- SysUtils,
- Classes,
- Math,
+ Windows, SysUtils, Classes, Math, DateUtils,
IdURI,
- YofUtils in '..\..\YofUtils.pas',
PlugInMain in 'PlugInMain.pas',
ThreadItem in 'ThreadItem.pas',
BoardItem in 'BoardItem.pas',
- FilePath in 'FilePath.pas';
+ FilePath in 'FilePath.pas',
+ MojuUtils in '..\..\MojuUtils.pas';
{$R *.res}
private
FIsTemporary : Boolean;
FDat : TStringList;
-
+ //FFilePath : String;
public
constructor Create( inInstance : DWORD );
destructor Destroy; override;
private
function Download : TDownloadState;
+ function Write( inName : string; inMail : string; inMessage : string ) : TDownloadState;
function GetRes( inNo : Integer ) : string;
+ function GetDat( inNo : Integer ) : string;
function GetHeader( inOptionalHeader : string ) : string;
function GetFooter( inOptionalFooter : string ) : string;
+ function GetBoardURL : string;
- procedure To2chDat( ioHTML : TStringList );
+ procedure To2chDat( ioHTML : TStringList; inStartNo : Integer = 1 );
+ procedure LoadDat;
+ procedure FreeDat;
+ function ReadURL : string;
+ //property FilePath : string read FFilePath;
end;
// =========================================================================
private
function Download : TDownloadState;
+ function CreateThread( inSubject : string; inName : string; inMail : string; inMessage : string ) : TDownloadState;
function ToThreadURL( inFileName : string ) : string;
procedure EnumThread( inCallBack : TBoardItemEnumThreadCallBack );
+ function SubjectURL : string;
end;
// =========================================================================
const
LOG_DIR = 'MachiBBS\';
+ SUBJECT_NAME = 'subject.txt';
PLUGIN_NAME = 'MachiBBSPlugIn';
MAJOR_VERSION = 1;
MINOR_VERSION = 0;
- RELEASE_VERSION = 'alpha';
- REVISION_VERSION = 1;
+ RELEASE_VERSION = 'beta';
+ REVISION_VERSION = 20;
// =========================================================================
// \8eG\97p\8aÖ\90\94
// *************************************************************************
function MyLogFolder : string;
var
- folder : string;
+ folder : PChar;
begin
folder := LogFolder;
Result := ''
else
Result := folder + LOG_DIR;
+ DisposeResultString(folder);
end;
Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
end;
+// \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
+procedure ExtractHttpFields(
+ const chrSep : TSysCharSet;
+ const chrWhite : TSysCharSet;
+ const strValue : string;
+ var strResult : TStringList;
+ unknownFlag : boolean = false
+);
+var
+ last, p, strLen : Integer;
+begin
+
+ strLen := Length( strValue );
+ p := 1;
+ last := 1;
+
+ while p <= strLen do
+ begin
+
+ if strValue[ p ] in chrSep then
+ begin
+ strResult.Add( Copy( strValue, last, p - last ) );
+ last := p + 1;
+ end;
+
+ p := p + 1;
+
+ end;
+
+ if last <> p then
+ strResult.Add( Copy( strValue, last, strLen - last + 1 ) );
+
+end;
+
+\rfunction HttpEncode(
+\r const strValue : string
+) : string;
+var
+ i : Integer;
+ strLen : Integer;
+ strResult : string;
+ b : Integer;
+const
+ kHexCode : array [0..15] of char = (
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' );
+begin
+
+ strLen := Length( strValue );
+ i := 1;
+
+ while i <= strLen do
+ begin
+
+ case strValue[ i ] of
+ '0' .. '9', 'a' .. 'z', 'A' .. 'Z', '*', '-', '.', '@', '_':
+ begin
+ strResult := strResult + strValue[ i ];
+ end;
+ else
+ begin
+ b := Integer( strValue[ i ] );
+ strResult := strResult + '%'
+ + kHexCode[ b div $10 ]
+ + kHexCode[ b mod $10 ];
+ end;
+ end;
+
+ i := i + 1;
+
+ end;
+
+ Result := strResult;
+
+end;
+
// =========================================================================
// \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©
// *************************************************************************
function OnAcceptURL(
- inURL : PChar // \94»\92f\82ð\8bÂ\82¢\82Å\82¢\82é URL
-): Boolean; stdcall; // \8eó\82¯\95t\82¯\82é\82È\82ç True
+ inURL : PChar // \94»\92f\82ð\8bÂ\82¢\82Å\82¢\82é URL
+): TAcceptType; stdcall; // URL \82Ì\8eí\97Þ
var
- URI : TIdURI;
- foundPos : Integer;
+ uri : TIdURI;
+ uriList : TStringList;
+ foundPos : Integer;
const
- BBS_HOST = 'machi.to';
+ BBS_HOST = 'machi.to';
+ THREAD_MARK = '/bbs/read.pl';
+ THREAD_MARK2= '/bbs/read.cgi';
begin
try
- // \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é
- URI := TIdURI.Create( inURL );
+ // \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é
+ uri := TIdURI.Create( inURL );
+ uriList := TStringList.Create;
try
- foundPos := Pos( BBS_HOST, URI.Host );
- Result := (foundPos > 0) and (Length( URI.Host ) - foundPos + 1 = Length( BBS_HOST ))
+ ExtractHttpFields( ['/'], [], uri.Path, uriList );
+ foundPos := AnsiPos( BBS_HOST, uri.Host );
+ if (foundPos > 0) and (Length( uri.Host ) - foundPos + 1 = Length( BBS_HOST )) then begin
+ foundPos := Pos( THREAD_MARK, inURL );
+ if (foundPos = 0) then begin
+ // \90VURL\91Î\89\9e
+ foundPos := Pos( THREAD_MARK2, inURL );
+ end;
+ if foundPos > 0 then
+ Result := atThread
+ else if (uriList.Count > 1) and (uri.Path <> '/') then // \8dÅ\8cã\82ª '/' \82Å\95Â\82ß\82ç\82ê\82Ä\82é\82È\82ç 3
+ Result := atBoard
+ else
+ Result := atBBS;
+ end else begin
+ Result := atNoAccept;
+ end;
finally
- URI.Free;
+ uri.Free;
+ uriList.Free;
end;
except
- Result := False;
+ Result := atNoAccept;
end;
end;
+// *************************************************************************
+// \8ew\92è\82µ\82½ URL \82ðBoard\82ÌURL\82É\95Ï\8a·
+// *************************************************************************
+procedure OnExtractBoardURL(
+ inURL : PChar;
+ var outURL : PChar
+); stdcall;
+var
+ uri : TIdURI;
+ uriList : TStringList;
+ URL : String;
+const
+ THREAD_MARK = '/bbs/read.pl';
+ THREAD_MARK2= '/bbs/read.cgi';
+begin
+ URL := string(inURL);
+ if AnsiPos(THREAD_MARK, URL) > 0 then begin
+ if Copy( inURL, Length( inURL ), 1 ) = '/' then
+ uri := TIdURI.Create( URL )
+ else
+ uri := TIdURI.Create( URL + '/' );
+
+ uriList := TStringList.Create;
+ try
+ ExtractHttpFields(
+ ['&'], [],
+ Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ),uriList );
+ // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
+ // http://hokkaido.machi.to/hokkaidou/
+ URL := uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/';
+ outURL := CreateResultString(URL);
+ finally
+ uri.Free;
+ uriList.Free;
+ end;
+ end else if AnsiPos(THREAD_MARK2, URL) > 0 then begin
+ if Copy( inURL, Length( inURL ), 1 ) = '/' then
+ uri := TIdURI.Create( URL )
+ else
+ uri := TIdURI.Create( URL + '/' );
+
+ uriList := TStringList.Create;
+ try
+ // http://kanto.machi.to/bbs/read.cgi/kana/1215253035/l50
+ // http://kanto.machi.to/kana/
+ uriList.Delimiter := '/';
+ uriList.DelimitedText := uri.Path;
+ URL := uri.Protocol + '://' + uri.Host + '/';
+ if (uriList.Count >= 4) then begin
+ URL := URL + uriList[3] + '/';
+ end;
+ outURL := CreateResultString(URL);
+ finally
+ uri.Free;
+ uriList.Free;
+ end;
+ end else begin
+ outURL := CreateResultString(URL);
+ end;
+
+end;
// =========================================================================
var
uri : TIdURI;
uriList : TStringList;
+ FilePath : String;
begin
inherited;
OnDownload := Download;
+ OnWrite := Write;
OnGetRes := GetRes;
+ OnGetDat := GetDat;
OnGetHeader := GetHeader;
OnGetFooter := GetFooter;
+ OnGetBoardURL := GetBoardURL;
- FilePath := '';
+ //FFilePath := '';
FIsTemporary := False;
FDat := nil;
+ URL := ReadURL + '&LAST=50';
uri := TIdURI.Create( URL );
uriList := TStringList.Create;
try
// http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
- YofUtils.ExtractHttpFields(
+ ExtractHttpFields(
['&'], [],
- Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+ Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
FileName := uriList.Values[ 'KEY' ] + '.dat';
FilePath := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
IsLogFile := FileExists( FilePath );
destructor TMachiBBSThreadItem.Destroy;
begin
- if FDat <> nil then begin
- try
- FDat.Free;
- FDat := nil;
- except
- end;
- end;
+ FreeDat;
// \88ê\8e\9e\83t\83@\83C\83\8b\82Ì\8fê\8d\87\82Í\8dí\8f\9c\82·\82é
if FIsTemporary then
modified : Double;
tmp : PChar;
downResult : TStringList;
+ content : TStringList;
responseCode : Longint;
logStream : TFileStream;
uri : TIdURI;
uriList : TStringList;
datURL : string;
foundPos : Integer;
+ FilePath : String;
+ procedure downAndParse;
+ begin
+ responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
+
+ try
+ if responseCode = 200 then begin
+ downResult := TStringList.Create;
+ try
+ downResult.Text := string( tmp );
+
+ // \83^\83C\83g\83\8b\82Ì\8eæ\93¾
+ foundPos := AnsiPos( '<title>', downResult.Text ) + Length( '<title>' );
+ Title := Copy(
+ downResult.Text,
+ foundPos,
+ AnsiPos( '</title>', downResult.Text ) - foundPos );
+
+ // \83\8c\83X\82Ì\8aJ\8en\88Ê\92u
+ foundPos := AnsiPos( '<dt', downResult.Text );
+ downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
+ if foundPos > 0 then begin
+ // \83\8c\83X\82Ì\8fI\97¹\88Ê\92u
+ foundPos := AnsiPos( '<table', downResult.Text ) - 1;
+ if foundPos > 0 then
+ downResult.Text := Copy( downResult.Text, 1, foundPos );
+ // \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Å
+ // \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¤
+ To2chDat( downResult, Count + 1 );
+ content.Text := content.Text + downResult.Text;
+ end;
+ finally
+ downResult.Free;
+ end;
+ end else begin
+ Result := dsNotModify;
+ Exit;
+ end;
+ finally
+ DisposeResultString( tmp );
+ end;
+ end;
begin
Result := dsError;
uri := TIdURI.Create( URL );
- uriList := TStringList.Create;
+ uriList := TStringList.Create;
+ content := TStringList.Create;
try
- YofUtils.ExtractHttpFields(
+ ExtractHttpFields(
['&'], [],
- Copy( uri.Params, Pos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+ Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+ FileName := uriList.Values[ 'KEY' ] + '.dat';
if MyLogFolder = '' then begin
// \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¶
FilePath := TemporaryFile;
// \95Û\91¶\97p\82Ì\83f\83B\83\8c\83N\83g\83\8a\82ð\8c@\82é
ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
- if FileExists( FilePath ) then
- logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite )
+ // \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Í
+ // InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
+ modified := LastModified;
+ if Count = 0 then
+ // 1\81`
+ datURL :=
+ uri.Protocol + '://' + uri.Host + '/bbs/read.cgi?' +
+ 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
+ '&START=' + IntToStr( 1 )
else
- logStream := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
- try
- // \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Í
- // InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
- modified := LastModified;
- // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
- // 1 + \90V\92\85
+ // \90V\92\85\82Ì\82Ý
datURL :=
- uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+ uri.Protocol + '://' + uri.Host + '/bbs/read.cgi?' +
'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
- '&START=' + IntToStr( Count + 1 );
- responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
-
- try
- if responseCode = 200 then begin
- downResult := TStringList.Create;
- try
- downResult.Text := string( tmp );
-
- // \83\8c\83X\82Ì\8aJ\8en\88Ê\92u
- foundPos := Pos( '<dt', downResult.Text );
- downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
- if foundPos > 0 then begin
- // \83\8c\83X\82Ì\8fI\97¹\88Ê\92u
- foundPos := Pos( '<table', downResult.Text ) - 1;
- if foundPos > 0 then
- downResult.Text := Copy( downResult.Text, 1, foundPos );
-
- // \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Å
- // \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¤
- To2chDat( downResult );
-
- if Count = 0 then begin
- Result := dsComplete
- end else begin
- if downResult.Count > 0 then
- // \8dÅ\8f\89\82Í\95K\82¸ 1 \82Ì\83\8c\83X
- downResult.Delete( 0 );
- Result := dsDiffComplete;
- end;
- if downResult.Count > 0 then begin
- logStream.Position := logStream.Size;
- logStream.Write( PChar( downResult.Text )^, Length( downResult.Text ) );
-
- LastModified := modified;
- IsLogFile := True;
- NewReceive := Count + 1;
- Count := Count + downResult.Count;
- NewResCount := downResult.Count;
- end else begin
- Result := dsNotModify;
- end;
- end;
- finally
- downResult.Free;
- end;
+ '&START=' + IntToStr( Count + 1 ) + '&NOFIRST=TRUE';
+ // \83_\83E\83\93\83\8d\81[\83h
+ downAndParse;
+
+ if content.Count > 0 then begin
+ if Count <= 0 then begin
+ Result := dsComplete;
+ // \90V\8bK\8f\91\82«\8d\9e\82Ý
+ content[ 0 ] := content[ 0 ] + Title;
+ logStream := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
+ try
+ logStream.Position := logStream.Size;
+ logStream.Write( PChar( content.Text )^, Length( content.Text ) );
+ finally
+ logStream.Free;
end;
- finally
- DisposeResultString( tmp );
+ NewReceive := 1;
+ Count := content.Count;
+ end else begin
+ if (content.Count > 1) or (Trim(content.Text) <> '') then begin
+ Result := dsDiffComplete;
+ // \92Ç\8bL
+ logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite );
+ try
+ logStream.Position := logStream.Size;
+ logStream.Write( PChar( content.Text )^, Length( content.Text ) );
+ finally
+ logStream.Free;
+ end;
+ NewReceive := Count + 1;
+ Count := Count + content.Count;
+ end else begin
+ Result := dsNotModify;
+ end;
end;
- finally
- logStream.Free;
+ if (Result <> dsNotModify) then begin
+ // CGI \82©\82ç\82Í\90³\82µ\82¢\93ú\95t\82ª\93¾\82ç\82ê\82È\82¢\82Ì\82Å\8c»\8dÝ\82É\90Ý\92è
+ LastModified := Now;
+ NewResCount := content.Count;
+ end;
+ end else begin
+ Result := dsNotModify;
end;
finally
uri.Free;
uriList.Free;
+ content.Free;
+ end;
+
+end;
+
+// *************************************************************************
+// \8f\91\82«\8d\9e\82Ý\82ð\8ew\8e¦\82³\82ê\82½
+// *************************************************************************
+function TMachiBBSThreadItem.Write(
+ inName : string; // \96¼\91O(\83n\83\93\83h\83\8b)
+ inMail : string; // \83\81\81[\83\8b\83A\83h\83\8c\83X
+ inMessage : string // \96{\95¶
+) : TDownloadState; // \8f\91\82«\8d\9e\82Ý\82ª\90¬\8c÷\82µ\82½\82©\82Ç\82¤\82©
+var
+ postURL : string;
+ postData : string;
+ postResult : PChar;
+ uri : TIdURI;
+ uriList : TStringList;
+begin
+
+ uri := TIdURI.Create( URL );
+ uriList := TStringList.Create;
+ try
+ ExtractHttpFields(
+ ['&'], [],
+ Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+
+ postURL := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
+ postData :=
+ 'NAME=' + HttpEncode( inName ) +
+ '&MAIL=' + HttpEncode( inMail ) +
+ '&MESSAGE=' + HttpEncode( inMessage ) +
+ '&BBS=' + uriList.Values[ 'BBS' ] +
+ '&KEY=' + uriList.Values[ 'KEY' ] +
+ '&TIME=' + IntToStr( DateTimeToUnix( Now ) ) +
+ '&submit=' + HttpEncode( '\8f\91\82«\8d\9e\82Þ' );
+
+ // \93Æ\8e©\82É\92Ê\90M\82µ\82È\82¢\8fê\8d\87\82Í InternalPost \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
+ InternalPost( PChar( postURL ), PChar( postData ),PChar(URL), postResult );
+ DisposeResultString( postResult );
+
+ Result := dsComplete
+ finally
+ uri.Free;
+ uriList.Free;
end;
end;
// \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
// InternalAbon \82¨\82æ\82Ñ Dat2HTML \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
- if FDat = nil then begin
- if IsLogFile then begin
- // dat \82Ì\93Ç\82Ý\8d\9e\82Ý
- FDat := TStringList.Create;
- FDat.LoadFromFile( FilePath );
- end else begin
- // \83\8d\83O\82É\91¶\8dÝ\82µ\82È\82¢\82Ì\82Å\82±\82Ì\82Ü\82Ü\8fI\97¹
- Result := '';
- Exit;
- end;
+ LoadDat;
+ if (FDat = nil) or (inNo - 1 < 0 ) or (inNo - 1 >= FDat.Count) then begin
+ // \83\8d\83O\82É\91¶\8dÝ\82µ\82È\82¢\82Ì\82Å\82±\82Ì\82Ü\82Ü\8fI\97¹
+ Result := '';
+ Exit;
end;
res := FDat[ inNo - 1 ];
- tmp := InternalAbon( PChar( res ) );
- try
+ tmp := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
+ try
Result := Dat2HTML( string( tmp ), inNo );
finally
DisposeResultString( tmp );
end;
// *************************************************************************
+// \83\8c\83X\94Ô\8d\86 inNo \82É\91Î\82·\82é Dat \82ð\97v\8b\81\82³\82ê\82½
+// *************************************************************************
+function TMachiBBSThreadItem.GetDat(
+ inNo : Integer // \97v\8b\81\82³\82ê\82½\83\8c\83X\94Ô\8d\86
+) : string; // \82Q\82¿\82á\82ñ\82Ë\82é\82ÌDat\8c`\8e®
+var
+ //res: string;
+ tmp: PChar;
+begin
+ //Result := '';
+ // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
+ LoadDat;
+ if (FDat = nil) or (inNo - 1 < 0 ) or (inNo - 1 >= FDat.Count) then begin
+ // \83\8d\83O\82É\91¶\8dÝ\82µ\82È\82¢\82Ì\82Å\82±\82Ì\82Ü\82Ü\8fI\97¹
+ tmp := CreateResultString('');
+ Result := tmp;
+ DisposeResultString(tmp);
+ Exit;
+ end;
+ tmp := CreateResultString(FDat[ inNo - 1]);
+ try
+ Result := string(tmp);
+ finally
+ DisposeResultString(tmp);
+ end;
+
+end;
+
+// *************************************************************************
// \83X\83\8c\83b\83h\82Ì\83w\83b\83_ html \82ð\97v\8b\81\82³\82ê\82½
// *************************************************************************
function TMachiBBSThreadItem.GetHeader(
// GetRes \82ð\8cÄ\82Î\82ê\82é\82±\82Æ\82ª\97\\91z\82³\82ê\82é\82Ì\82Å FDat \82ð\90¶\90¬\82µ\82Ä\82¨\82
- if FDat <> nil then begin
- try
- FDat.Free;
- FDat := nil;
- except
- end;
- end;
- if IsLogFile then begin
- // dat \82Ì\93Ç\82Ý\8d\9e\82Ý
- FDat := TStringList.Create;
- FDat.LoadFromFile( FilePath );
+ try
+ FreeDat;
+ LoadDat;
+ except
end;
end;
// \82à\82¤ GetRes \82Í\8cÄ\82Î\82ê\82È\82¢\82Æ\8ev\82¤\82Ì\82Å FDat \82ð\8aJ\95ú\82µ\82Ä\82¨\82
try
- if FDat <> nil then begin
- FDat.Free;
- FDat := nil;
- end;
+ FreeDat;
except
end;
end;
// *************************************************************************
+// \82±\82Ì ThreadItem \82ª\91®\82·\82é\94Â\82Ì URL \82ð\97v\8b\81\82³\82ê\82½
+// *************************************************************************
+function TMachiBBSThreadItem.GetBoardURL : string;
+var
+ uri : TIdURI;
+ uriList : TStringList;
+ tmp: PChar;
+begin
+ tmp := nil;
+ if Copy( URL, Length( URL ), 1 ) = '/' then
+ uri := TIdURI.Create( URL )
+ else
+ uri := TIdURI.Create( URL + '/' );
+ uriList := TStringList.Create;
+ try
+ ExtractHttpFields(
+ ['&'], [],
+ Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+ FileName := uriList.Values[ 'KEY' ] + '.dat';
+ // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
+ // http://hokkaido.machi.to/hokkaidou/
+ tmp := CreateResultString(
+ uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/' );
+ Result := string(tmp);
+ finally
+ DisposeResultString(tmp);
+ uri.Free;
+ uriList.Free;
+ end;
+
+end;
+
+// *************************************************************************
// \82Ü\82¿BBS\82Ì HTML \82ð 2ch \82Ì dat \8c`\8e®\82É
// *************************************************************************
procedure TMachiBBSThreadItem.To2chDat(
- ioHTML : TStringList
+ ioHTML : TStringList;
+ inStartNo : Integer = 1
);
var
- i, bound : Integer;
- foundPos : Integer;
- strTmp : string;
- res : TStringList;
+ i, bound : Integer;
+ foundPos,foundPos2 : Integer;
+ strTmp : string;
+ res : TStringList;
+ no : Integer;
const
- MAIL_TAG = '<a href="mailto:';
+ MAIL_TAG = '<a href="mailto:';
begin
//===== 2ch \82Ì dat \8c`\8e®\82É\95Ï\8a·
// \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
- ioHTML.Text := StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, #13#10, '');
+ //StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
// \91ã\82í\82è\82É <dt> \82ð\8ds\82Ì\8bæ\90Ø\82è\82É\82·\82é
- ioHTML.Text := StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '<dt>', #10 );
+ //StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
// <dt> \82©\82ç\8en\82Ü\82Á\82Ä\82¢\82é\82Ì\82Å\8dÅ\8f\89\82Í\8bó\82Ì\82Í\82¸
if Length( ioHTML[ 0 ] ) = 0 then
ioHTML.Delete( 0 );
+
+ // \8cy\82\82 \82Ú\81[\82ñ\83`\83F\83b\83N
+ // \81¦\91å\8eG\94c\82¾\82©\82ç\82¿\82á\82ñ\82Æ\8fo\97\88\82Ä\82È\82¢\82©\82à
+ try
+ i := 0;
+ while i < ioHTML.Count do begin
+ foundPos := AnsiPos( ' ', ioHTML[ i ] );
+ if foundPos > 0 then begin
+ no := StrToInt( Copy( ioHTML[ i ], 1, foundPos - 1 ) );
+ if inStartNo < no then
+ ioHTML.Insert( i, '<><><><>' );
+ end;
+ Inc( i );
+ Inc( inStartNo );
+ end;
+ except
+ // \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Å
+ end;
+
+
// \83g\83\8a\83b\83v\82Ì\8cã\82Ì '<b> </b>' \82ð\8bó\82É
- ioHTML.Text := StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
+ if AnsiPos('\81\9f</b>', ioHTML.Text) <> 0 then begin
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </b></font>', '</b></font>', true );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </B></a>', '</b></a>', true );
+ end;
+ //ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b> </b>', '', true );
+ //StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
// '<b>' \82Í\83\81\81[\83\8b\82Æ\96¼\91O\82Ì\8bæ\90Ø\82è
- ioHTML.Text := StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '<b>', '<>', true );
+ //StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
// \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É
- ioHTML.Text := StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
- ioHTML.Text := StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '</b></a>', '<>', true );
+ //StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '</b>', '<>', true );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '\81\9f<>', '\81\9f</b>', true );
+ //StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
// '<dd>' \82ð\96{\95¶\82Æ\82Ì\8bæ\90Ø\82è\82É
- ioHTML.Text := StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
+ ioHTML.Text := CustomStringReplace( ioHTML.Text, '<dd>', '<>', true );
+ //StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
res := TStringList.Create;
try
bound := ioHTML.Count - 1;
for i := 0 to bound do begin
- res.Text := StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
+ // \83X\83N\83\8a\83v\83g\82ª\8aÜ\82Ü\82ê\82Ä\82¢\82½\82ç\8dí\8f\9c\82·\82é\81i\8dL\8d\90\91Î\8dô\81j
+ res.Text := CustomStringReplace( ioHTML[ i ], '<>', #10 );
+ //StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
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ß
- foundPos := Pos( MAIL_TAG, res[ 0 ] );
+ foundPos := AnsiPos( MAIL_TAG, res[ 0 ] );
if foundPos > 0 then begin
// \83\81\81[\83\8b\83A\83h\83\8c\83X\82ð\94²\82«\8fo\82·
foundPos := foundPos + Length( MAIL_TAG );
res[ 0 ] := Copy( res[ 0 ], foundPos, Length( res[ 0 ] ) );
- strTmp := Copy( res[ 0 ], 1, Pos( '">', res[ 0 ] ) - 1 );
+ strTmp := Copy( res[ 0 ], 1, AnsiPos( '">', res[ 0 ] ) - 1 );
// \83\81\81[\83\8b\82Æ\96¼\91O\82ª\8bt\82È\82Ì\82Å\82Ð\82Á\82\82è\95Ô\82µ\82Ä\96ß\82·
res[ 0 ] := res[ 1 ];
res[ 1 ] := strTmp;
res[ 0 ] := res[ 1 ];
res[ 1 ] := '';
end;
- res[ 2 ] := StringReplace( res[ 2 ], '[', 'ID:', [] );
+ res[ 2 ] := StringReplace( res[ 2 ], '[', 'IP:', [] );
res[ 2 ] := StringReplace( res[ 2 ], ']', '', [] );
+
+ if AnsiPos('</font> \93\8a\8de\93ú\81F', res[ 2 ]) = 1 then begin
+ res[ 2 ] := StringReplace( res[ 2 ], '</font> \93\8a\8de\93ú\81F', '', [] );
+ end else if AnsiPos(' \93\8a\8de\93ú\81F', res[ 2 ]) = 1 then begin
+ res[ 2 ] := StringReplace( res[ 2 ], ' \93\8a\8de\93ú\81F', '', [] );
+ end;
end;
- ioHTML[ i ] := StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
+ ioHTML[ i ] := CustomStringReplace( res.Text, #13#10, '<>');
+ // \8dL\8d\90\83X\83N\83\8a\83v\83g\91Î\8dô
+ foundPos := Pos( '<script', ioHTML[ i ] );
+ if foundPos > 0 then begin
+ foundPos2 := Pos( '</script>', ioHTML[ i ] );
+ if (foundPos2 > foundPos) then begin
+ ioHTML[ i ] := Copy(ioHTML[ i ], 1, foundPos-1) +
+ Copy(ioHTML[ i ], foundPos2 + 9, Length(ioHTML[ i ]));
+ end;
+ end;
end;
finally
res.Free;
end;
// *************************************************************************
+// FDat \82Ì\90¶\90¬
+// *************************************************************************
+procedure TMachiBBSThreadItem.LoadDat;
+begin
+
+ if FDat = nil then begin
+ if IsLogFile then begin
+ // dat \82Ì\93Ç\82Ý\8d\9e\82Ý
+ FDat := TStringList.Create;
+ FDat.LoadFromFile( FilePath );
+ end;
+ end;
+
+end;
+
+// *************************************************************************
+// FDat \82Ì\8aJ\95ú
+// *************************************************************************
+procedure TMachiBBSThreadItem.FreeDat;
+begin
+
+ if FDat <> nil then begin
+ FDat.Free;
+ FDat := nil;
+ end;
+
+end;
+
+// *************************************************************************
+// \88À\91S\82È( '/' \82Å\8fI\82í\82é )\93Ç\82Ý\8d\9e\82Ý\82Ì URL
+// *************************************************************************
+function TMachiBBSThreadItem.ReadURL : string;
+var
+ uri : TIdURI;
+ uriList : TStringList;
+ foundPos : Integer;
+const
+ THREAD_MARK2= '/bbs/read.cgi';
+begin
+
+ foundPos := AnsiPos( '?', URL );
+ if foundPos > 0 then begin
+ uri := TIdURI.Create( URL );
+ uriList := TStringList.Create;
+ try
+ ExtractHttpFields( ['&'], [], Copy( URL, foundPos + 1, MaxInt ), uriList );
+ Result :=
+ uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+ 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ];
+ finally
+ uri.Free;
+ uriList.Free;
+ end;
+ end else begin
+ // \90V\8c`\8e® ?
+ foundPos := AnsiPos(THREAD_MARK2, URL);
+ if (foundPos > 0) then begin
+ uri := TIdURI.Create( URL );
+ uriList := TStringList.Create;
+ try
+ uriList.Delimiter := '/';
+ uriList.DelimitedText := uri.Path;
+ if (uriList.Count >= 5) then begin
+ Result :=
+ uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
+ 'BBS=' + uriList[3] + '&KEY=' + uriList[4];
+ end;
+ finally
+ uri.Free;
+ uriList.Free;
+ end;
+ end;
+ end;
+
+end;
+
+// *************************************************************************
// TThreadItem \82ª\90¶\90¬\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSThreadItem \82ð\90¶\90¬\82·\82é)
// *************************************************************************
procedure ThreadItemOnCreateOfTMachiBBSThreadItem(
inherited;
OnDownload := Download;
+ OnCreateThread := CreateThread;
OnEnumThread := EnumThread;
OnFileName2ThreadURL := ToThreadURL;
FilePath := '';
FIsTemporary := False;
FDat := nil;
+ Is2ch := False;
- if Copy( URL, Length( URL ), 1 ) = '/' then
- uri := TIdURI.Create( URL )
- else
- uri := TIdURI.Create( URL + '/' );
- uriList := TStringList.Create;
+ uri := TIdURI.Create( SubjectURL );
+ uriList := TStringList.Create;
try
- YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
+ ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
// http://hokkaido.machi.to/hokkaidou/subject.txt
FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
IsLogFile := FileExists( FilePath );
responseCode : Longint;
uri : TIdURI;
uriList : TStringList;
-const
- SUBJECT_NAME = 'subject.txt';
begin
Result := dsError;
- if Copy( URL, Length( URL ), 1 ) = '/' then
- uri := TIdURI.Create( URL + SUBJECT_NAME )
- else
- uri := TIdURI.Create( URL );
- uriList := TStringList.Create;
if FDat <> nil then begin
try
FDat.Free;
except
end;
end;
- FDat := TStringList.Create;
+ FDat := TStringList.Create;
+ uri := TIdURI.Create( SubjectURL );
+ uriList := TStringList.Create;
// \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Í
// InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
- modified := LastModified;
- responseCode := InternalDownload( PChar( uri.URI ), modified, downResult );
+ modified := LastModified;
+ responseCode := InternalDownload( PChar( uri.URI ), modified, downResult );
try
if responseCode = 200 then begin
try
// \83p\83X\82ð\8eZ\8fo
- YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
+ ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
if MyLogFolder = '' then begin
// \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¶
FilePath := TemporaryFile;
FDat.Text := string( downResult );
// \95Û\91¶
FDat.SaveToFile( FilePath );
+
+ IsLogFile := True;
+ RoundDate := Now;
+ LastModified := modified;
+ LastGetTime := Now;
finally
uri.Free;
uriList.Free;
end;
// *************************************************************************
+// \83X\83\8c\97§\82Ä\82ð\8ew\8e¦\82³\82ê\82½
+// *************************************************************************
+function TMachiBBSBoardItem.CreateThread(
+ inSubject : string; // \83X\83\8c\83^\83C
+ inName : string; // \96¼\91O(\83n\83\93\83h\83\8b)
+ inMail : string; // \83\81\81[\83\8b\83A\83h\83\8c\83X
+ inMessage : string // \96{\95¶
+) : TDownloadState; // \8f\91\82«\8d\9e\82Ý\82ª\90¬\8c÷\82µ\82½\82©\82Ç\82¤\82©
+var
+ postURL : string;
+ postData : string;
+ postResult : PChar;
+ uri : TIdURI;
+ uriList : TStringList;
+begin
+
+ uri := TIdURI.Create( URL );
+ uriList := TStringList.Create;
+ try
+ ExtractHttpFields(
+ ['&'], [],
+ Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
+
+ postURL := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
+ postData :=
+ 'SUBJECT=' + HttpEncode( inSubject ) +
+ '&NAME=' + HttpEncode( inName ) +
+ '&MAIL=' + HttpEncode( inMail ) +
+ '&MESSAGE=' + HttpEncode( inMessage ) +
+ '&BBS=' + uriList[ 1 ] +
+ '&TIME=' + IntToStr( DateTimeToUnix( Now ) ) +
+ '&submit=' + HttpEncode( '\90V\8bK\8f\91\82«\8d\9e\82Ý' );
+
+ // \93Æ\8e©\82É\92Ê\90M\82µ\82È\82¢\8fê\8d\87\82Í InternalPost \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
+ InternalPost( PChar( postURL ), PChar( postData ),PChar(URL), postResult );
+ DisposeResultString( postResult );
+
+ Result := dsComplete
+ finally
+ uri.Free;
+ uriList.Free;
+ end;
+
+end;
+
+// *************************************************************************
// \83X\83\8c\88ê\97\97\82Ì URL \82©\82ç\83X\83\8c\83b\83h\82Ì URL \82ð\93±\82«\8fo\82·
// *************************************************************************
function TMachiBBSBoardItem.ToThreadURL(
found : Integer;
begin
- found := Pos( '.', inFileName );
+ found := AnsiPos( '.', inFileName );
if found > 0 then
inFileName := Copy( inFileName, 1, found - 1 );
- if Copy( URL, Length( URL ), 1 ) = '/' then
- uri := TIdURI.Create( URL )
- else
- uri := TIdURI.Create( URL + '/' );
- uriList := TStringList.Create;
+ uri := TIdURI.Create( SubjectURL );
+ uriList := TStringList.Create;
try
try
// http://hokkaido.machi.to/hokkaidou/
// http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
- YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
+ ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
threadURL := uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
'BBS=' + uriList[ 1 ] + '&KEY=' + inFileName + '&LAST=50';
Result := threadURL;
var
uri : TIdURI;
uriList : TStringList;
-const
- SUBJECT_NAME = 'subject.txt';
begin
try
if FDat = nil then begin
FDat := TStringList.Create;
- if Copy( URL, Length( URL ), 1 ) = '/' then
- uri := TIdURI.Create( URL + SUBJECT_NAME )
- else
- uri := TIdURI.Create( URL );
- uriList := TStringList.Create;
+ uri := TIdURI.Create( SubjectURL );
+ uriList := TStringList.Create;
try
// \83p\83X\82ð\8eZ\8fo
- YofUtils.ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
+ ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
// http://hokkaido.machi.to/hokkaidou/subject.txt
FilePath := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
if FileExists( FilePath ) then
end;
// \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é
- inherited EnumThread( inCallBack, FDat.Text );
+ inherited EnumThread( inCallBack, CustomStringReplace( FDat.Text, ',', '<>' ) );
except
end;
end;
// *************************************************************************
+// \83X\83\8c\88ê\97\97\82Ì URL \82ð\8b\81\82ß\82é
+// *************************************************************************
+function TMachiBBSBoardItem.SubjectURL : string;
+var
+ uri : TIdURI;
+ uriList : TStringList;
+begin
+
+ uri := TIdURI.Create( URL );
+ uriList := TStringList.Create;
+ try
+ if uri.Document <> SUBJECT_NAME then begin
+ if Copy( URL, Length( URL ), 1 ) = '/' then
+ Result := URL + SUBJECT_NAME
+ else
+ Result := URL + '/' + SUBJECT_NAME;
+ end else begin
+ // \82±\82±\82É\82Í\97\88\82È\82¢\82Æ\8ev\82¤\82¯\82Ç
+ Result := URL;
+ end;
+ finally
+ uri.Free;
+ uriList.Free;
+ end;
+
+end;
+
+// *************************************************************************
// TBoardItem \82ª\90¶\90¬\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSBoardItem \82ð\90¶\90¬\82·\82é)
// *************************************************************************
procedure BoardItemOnCreateOfTMachiBBSBoardItem(
exports
OnVersionInfo,
- OnAcceptURL;
-
+ OnAcceptURL,
+ OnExtractBoardURL;
begin
try