You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RnQ/for.RnQ/RnQNet.pas

1165 lines
35 KiB
Plaintext

unit RnQNet;
{$I forRnQConfig.inc}
{ $I RnQConfig.inc }
interface
uses
Classes, Forms, JSON, NetEncoding, OverbyteIcsHttpProt, OverbyteIcsWSocket,
RDGlobal, RnQGlobal;
{$I NoRTTI.inc}
type
TProxyProto = (PP_NONE = 0, PP_SOCKS4 = 1, PP_SOCKS5 = 2, PP_HTTPS = 3);
THostPort = record
host: String;
port: Integer;
end;
TProxy = record
name: String;
user: String;
pwd: String; // Support Unicode!
auth: Boolean;
NTLM: Boolean;
proto: TproxyProto;
addr: Thostport;
end;
TICQFileInfo = record
jsonlink: String;
dlink: String;
mime: String;
filename: String;
is_previewable: Boolean;
preview: String;
end;
TArrProxy = array of TProxy;
const
ProxyProto2Str: array [TProxyProto] of String = ('NONE', 'SOCKS4', 'SOCKS5', 'HTTP/S');
procedure CopyProxy(var pTo: Tproxy; const pFrom: Tproxy);
procedure ClearProxy(var p1: Tproxy);
procedure CopyProxyArr(var pATo: TarrProxy; const pAFrom: TarrProxy);
procedure ClearProxyArr(var pa: TarrProxy);
type
TDataReceived = procedure(Sender: TObject; ErrCode: Word; pkt: RawByteString) of object;
TProxyLogData = procedure(Sender: TObject; isReceive: boolean; Data: RawByteString) of object;
(*
TRnQSocket = class(TSslWSocket)
private
FSocksConnected: boolean;
FOldOnSessionConnected: TSessionConnected;
FOldOnDataAvailable: TDataAvailable;
FServerAddr: String;
FServerPort: AnsiString;
FMyBeautifulSocketBuffer: RawByteString;
FOnDataReceived: TDataReceived;
FOnProxyTalk: TProxyLogData;
procedure myOnConnected(Sender: TObject; Error: Word);
procedure myOnReceived(Sender: TObject; Error: Word);
procedure ClientConnected(Sender: TObject; Error: Word);
procedure ClientConnected2(Sender: TObject; Error: Word);
public
fAccIDX: Integer;
isSSL: boolean;
procedure StartTLS;
protected
SslCtxt: TSslContext;
procedure SockSslHandshakeDone(Sender: TObject; ErrCode: Word; PeerCert: TX509Base; var Disconnect: boolean);
procedure TriggerSessionClosed(Error: Word); override;
function GetAddr1: String;
function GetAddr2: String;
procedure TriggerProxyData(isReceive: boolean; Data: RawByteString);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Connect; override;
procedure Close; override;
// procedure CloseDelayed; override;
procedure DisableProxy();
procedure getFreePort;
// function RealSend(Data : Pointer; Len : Integer) : Integer; override;
// function RealSend(var Data : TWSocketData; Len : Integer) : Integer; override;
// function Send(Data: Pointer; Len: Integer): Integer; override;
// function Send(const Data : TWSocketData; Len : Integer) : Integer; override;
// function SendStr(const Str : String) : Integer; override;
// function Receive(Buffer: Pointer; BufferSize: Integer): Integer; override;
// function Receive(Buffer : TWSocketData; BufferSize: Integer) : Integer; {overload; } override;
// function ReceiveStr: string; override;
property addr: String read GetAddr1 write SetAddr;
property AddrPort: String read GetAddr2;
property OnDataReceived: TDataReceived read FOnDataReceived write FOnDataReceived;
property OnProxyTalk: TProxyLogData read FOnProxyTalk write FOnProxyTalk;
end;
*)
TCallbacks = class
private
FOnBeforeHeaderSend: TBeforeHeaderSendEvent;
FOnSendData: TDocDataEvent;
FOnRequestDone: THttpRequestDone;
public
Data: Pointer;
property OnBeforeHeaderSend: TBeforeHeaderSendEvent read FOnBeforeHeaderSend write FOnBeforeHeaderSend;
property OnSendData: TDocDataEvent read FOnSendData write FOnSendData;
property OnRequestDone: THttpRequestDone read FOnRequestDone write FOnRequestDone;
end;
const
ConnectionError = 'Connection error\n%s\n[%d] %s';
SSLError = 'OpenSSL libs are not found\n%s';
FileTooBig = 'File is too big, max size %s MB';
AuthFailed = 'File hosting authentication failed';
UploadError = 'Failed to upload file! Server response';
ImageContentTypes: array [0 .. 25] of string = (
'image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap',
'image/jpeg', 'image/jpg', 'application/jpg', 'application/x-jpg',
'image/gif',
'image/png', 'application/png', 'application/x-png',
'image/ico', 'image/x-icon', 'application/ico', 'application/x-ico',
'image/tiff', 'image/x-tiff',
'image/webp'
);
ImageExtensions: array [0 .. 25] of string = (
'bmp', 'bmp', 'bmp', 'bmp', 'bmp', 'bmp', 'bmp', 'bmp', 'bmp', 'bmp', 'bmp',
'jpg', 'jpg', 'jpg', 'jpg',
'gif',
'png', 'png', 'png',
'ico', 'ico', 'ico', 'ico',
'tiff', 'tiff',
'webp'
);
function HeaderFromURL(const URL: String): String;
function UploadFileRGhost(FileStream: TStream; const FileName: String; UploadCallbacks: TCallbacks): String;
function UploadFileMikanoshi(FileStream: TStream; const FileName: String; UploadCallbacks: TCallbacks): String;
function UploadFileRnQ(FileStream: TStream; const FileName: String; UploadCallbacks: TCallbacks): String;
function CreateZip(str: TStringList): TMemoryStream;
function GetICQFileLinkInfo(const lnk: String): TICQFileInfo;
function CheckType(const lnk: String): Boolean; overload;
function CheckType(const lnk: String; var sA: RawByteString; var ext: String): Boolean; overload;
function DownloadAndCache(const lnk: String): Boolean;
procedure SetupProxy(var httpCli: TSslHttpCli);
procedure HandleError(E: EHttpException; const URL: String; const ErrText: String = ''; Quiet: Boolean = True);
function DecodeURL(const url: String): String;
function LoadFromURL(const URL: String; var fn: String; var fs: TMemoryStream; Threshold: LongInt = 0;
ExtByContent: Boolean = False; const POSTData: RawByteString = ''; ShowErrors: Boolean = true;
OutputAsStr: Boolean = False): Boolean; overload;
function LoadFromURL(const URL: String; var fn: String; Threshold: LongInt = 0; ExtByContent: Boolean = False;
const POSTData: RawByteString = ''; ShowErrors: Boolean = true): Boolean; overload;
function LoadFromURL(const URL: String; var fs: TMemoryStream; Threshold: LongInt = 0; ExtByContent: Boolean = False;
const POSTData: RawByteString = ''; ShowErrors: Boolean = true): Boolean; overload;
function LoadFromURLAsString(const URL: String; var str: String; const POSTData: RawByteString = ''): Boolean;
function LoadFromURLAsync(const URL: String; Callback: THttpRequestDone = nil; Data: Pointer = nil;
const POSTData: RawByteString = ''; ShowErrors: Boolean = True): Boolean;
var
MainProxy: Tproxy;
AllProxies: TarrProxy;
IsUploading: Boolean;
UploadSize: Int64;
UploadedSize: Int64;
SslCtx: TSslContext;
EnableVideoLinks: Boolean;
implementation
uses
Windows, Base64, SysUtils, StrUtils, System.Threading,
RDUtils, RnQPrefsLib, RnQZip,
{$IFDEF UNICODE}
AnsiStrings,
{$ENDIF UNICODE}
// OverbyteIcsLogger,
{$IFDEF RNQ}
RnQLangs, RnQDialogs, RQUtil, utilLib, ICQContacts, ICQSession, globalLib,
{$ENDIF RNQ}
{$IFDEF RNQ_PLUGIN}
RDPlugins,
{$ENDIF RNQ_PLUGIN}
RnQGraphics32;
Procedure CopyProxy(var pTo: Tproxy; const pFrom: Tproxy);
begin
// p1.enabled:= p2.enabled;
pTo.name := pFrom.name;
pTo.proto := pFrom.proto;
{ for pp:=low(pp) to high(pp) do
begin
proxy.addr[pp].host:=proxyes[lastProxy].addr[pp].host;
proxy.addr[pp].port:=proxyes[lastProxy].addr[pp].port;
end; }
pTo.addr.host := pFrom.addr.host;
pTo.addr.port := pFrom.addr.port;
pTo.user := pFrom.user;
pTo.pwd := pFrom.pwd;
pTo.auth := pFrom.auth;
pTo.NTLM := pFrom.NTLM;
end;
Procedure ClearProxy(var p1: Tproxy);
begin
p1.name := '';
p1.proto := PP_NONE;
{ for pp:=low(pp) to high(pp) do
begin
proxy.addr[pp].host:=proxyes[lastProxy].addr[pp].host;
proxy.addr[pp].port:=proxyes[lastProxy].addr[pp].port;
end; }
p1.addr.host := '';
p1.user := '';
p1.pwd := '';
end;
Procedure CopyProxyArr(var pATo: TarrProxy; const pAFrom: TarrProxy);
var
I: Integer;
begin
ClearProxyArr(pATo);
SetLength(pATo, Length(pAFrom));
if Length(pAFrom) > 0 then
for I := Low(pAFrom) to High(pAFrom) do
// ClearProxy(pa[i]);
CopyProxy(pATo[I], pAFrom[I]);
// SetLength(pa, 0);
end;
procedure ClearProxyArr(var pa: TarrProxy);
var
I: Integer;
begin
if Length(pa) > 0 then
begin
for I := Low(pa) to High(pa) do
ClearProxy(pa[I]);
SetLength(pa, 0);
end;
end;
{ TRnQSocket }
(*
constructor TRnQSocket.Create(AOwner: TComponent);
begin
inherited;
fAccIDX := -1;
SslCtxt := nil;
{ IcsLogger := TIcsLogger.Create(AOwner);
IcsLogger.LogFileName := 'sckt.log';
IcsLogger.LogOptions := [loDestFile, loWsockErr, loWsockInfo, loWsockDump,
// loSslErr, loSslInfo, loSslDump,
loProtSpecErr, loProtSpecInfo, loProtSpecDump];
}
end;
procedure TRnQSocket.Connect;
var
Mtd: Pointer;
begin
FSocksConnected := false;
FServerAddr := FAddrStr;
FServerPort := port;
if isSSL then
begin
OnSslHandshakeDone := SockSslHandshakeDone;
if not Assigned(SslCtxt) then
SslCtxt := TSslContext.Create(self);
// else
// SslCtxt.InitContext
// SslCtxt.IcsLogger := Self.IcsLogger;
// SslCtxt.SslVersionMethod := sslTLS_V1_CLIENT;
// SslCtxt.SslCipherList := 'ALL:eNULL:aNULL:@STRENGTH';
SslCtxt.SslCipherList := 'DEFAULT:@STRENGTH';
// SslCtxt.SslSessionCacheModes := [];
SslCtxt.SslVersionMethod := sslV23;
SslCtxt.SslVerifyPeer := false;
// SslCtxt.SslVerifyDepth := 1;
SslCtxt.SslVerifyPeerModes := [SslVerifyMode_NONE];
SslCtxt.SslVerifyDepth := 9;
SslContext := SslCtxt;
SslEnable := false;
SslMode := sslModeClient;
end;
inherited;
end;
destructor TRnQSocket.Destroy;
begin
SslContext := nil;
FreeAndNil(SslCtxt);
inherited;
end;
procedure TRnQSocket.TriggerProxyData(isReceive: boolean; Data: RawByteString);
begin
if Assigned(FOnProxyTalk) then
FOnProxyTalk(self, isReceive, Data);
end;
procedure TRnQSocket.myOnConnected(Sender: TObject; Error: Word);
var
// eventData, s : AnsiString;
vData, vRaw: RawByteString;
begin
if Error <> 0 then
begin
// if Assigned(FOldOnSessionConnected) then
// FOldOnSessionConnected(Sender, Error);
ClientConnected(Sender, Error);
Exit;
end;
ClientConnected(Sender, Error);
end;
procedure TRnQSocket.myOnReceived(Sender: TObject; Error: Word);
const
socksAuthenticationFailed = 20015;
var
pkt, s: RawByteString;
I, j: Integer;
eventError: Word;
begin
eventError := 0;
end;
procedure TRnQSocket.SockSslHandshakeDone(Sender: TObject; ErrCode: Word; PeerCert: TX509Base; var Disconnect: boolean);
begin
ClientConnected2(Sender, ErrCode);
end;
procedure TRnQSocket.StartTLS;
begin
isSSL := true;
begin
OnSslHandshakeDone := SockSslHandshakeDone;
if not Assigned(SslCtxt) then
SslCtxt := TSslContext.Create(self);
SslCtxt.SslCipherList := 'DEFAULT:@STRENGTH';
// SslCtxt.SslVersionMethod := sslV23;
SslCtxt.SslVersionMethod := sslTLS_V1;
SslCtxt.SslVerifyPeer := false;
// SslCtxt.SslVerifyDepth := 1;
SslCtxt.SslVerifyPeerModes := [SslVerifyMode_NONE];
SslCtxt.SslVerifyDepth := 9;
SslContext := SslCtxt;
SslMode := sslModeClient;
SslEnable := true;
StartSslHandshake;
end;
end;
procedure TRnQSocket.Close;
begin
if Assigned(FOldOnSessionConnected) then
FOnSessionConnected := FOldOnSessionConnected;
FOldOnSessionConnected := nil;
if Assigned(FOldOnDataAvailable) then
FOnDataAvailable := FOldOnDataAvailable;
FOldOnDataAvailable := nil;
// if not FSecureClient.Active then
// FErrorOccured := true;
inherited;
end;
procedure TRnQSocket.ClientConnected(Sender: TObject; Error: Word);
begin
if isSSL and (Error = 0) then
begin
try
self.SslEnable := true;
self.StartSslHandshake;
except
on E: Exception do
begin
if Assigned(FOnSocksError) then
FOnSocksError(self, 1001, E.Classname + ' ' + E.Message);
Close;
end;
end;
end
else
ClientConnected2(Sender, Error);
end;
procedure TRnQSocket.ClientConnected2(Sender: TObject; Error: Word);
var
FOldOnData: TDataAvailable;
begin
FSocksConnected := true;
if Assigned(FOldOnSessionConnected) then
begin
FOldOnData := FOnDataAvailable;
FOldOnSessionConnected(Sender, Error);
// if TMethod(FOnDataAvailable).Code <> TMethod(FOldOnData).Code then
// begin
// FOldOnDataAvailable := FOnDataAvailable;
// FOnDataAvailable := FOldOnData;
// end;
if Assigned(FOldOnDataAvailable) then
FOnDataAvailable := FOldOnDataAvailable;
FOldOnDataAvailable := nil;
end
else if Assigned(FOnSessionConnected) then
FOnSessionConnected(Sender, Error);
// if FSecureClient.Enabled and FSecureClient.Active then
// DoSSLEstablished();
end;
procedure TRnQSocket.DisableProxy();
begin
self.socksServer := '';
self.socksPort := '';
self.SocksAuthentication := socksNoAuthentication;
end;
procedure TRnQSocket.getFreePort;
begin
port := '0';
end;
{
procedure TRnQSocket.CloseDelayed;
begin
inherited;
end;
function TRnQSocket.RealSend(Data: Pointer; Len: Integer): Integer;
begin
end;
function TRnQSocket.Receive(Buffer: Pointer; BufferSize: Integer): Integer;
begin
end;
function TRnQSocket.ReceiveStr: string;
begin
end;
function TRnQSocket.Send(Data: Pointer; Len: Integer): Integer;
begin
end;
function TRnQSocket.SendStr(const Str: String): Integer;
begin
end;
}
procedure TRnQSocket.TriggerSessionClosed(Error: Word);
begin
// if FState <> wsClosed then begin
if FState = wsClosed then
begin
addr := FServerAddr;
port := FServerPort;
end;
inherited;
end;
function TRnQSocket.GetAddr1: String;
begin
// if FSocksConnected then
if FState = wsClosed then
Result := FAddrStr
else
Result := FServerAddr;
// else
// Addr;
end;
function TRnQSocket.GetAddr2: String;
begin
Result := GetAddr1 + ':' + port;
end;
*)
{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
{
function URLEncode(const Url: Utf8String): string;
var
i: Integer;
begin
Result := '';
for i := 1 to Length(Url) do
begin
if CharInSet(Url[I], ['A'..'Z', 'a'..'z', '0'..'9', ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '''', '(', ')', '*', '+', ',', ';', '=', '-', '_', '.', '~']) then
Result := Result + Utf8ToAnsi(Url[I])
else
Result := Result + '%' + IntToHex(Ord(Url[I]), 2);
end;
end;
}
function DecodeURL(const url: String): String;
begin
Result := TEncoding.UTF8.GetString(TNetEncoding.URL.DecodeStringToBytes(url));
end;
procedure HandleError(E: EHttpException; const URL: String; const ErrText: String = ''; Quiet: Boolean = True);
begin
if Assigned(E) then
TThread.Synchronize(nil, procedure begin
if E.ErrorCode = 3 then
msgDlg(GetTranslation(SSLError, [E.Message]), False, mtError)
else if (E.ErrorCode <> 404) or not Quiet then
begin
if (E.ErrorCode = 404) and URL.Contains('store_id=') then
Exit;
if not (ErrText = '') then
msgDlg(GetTranslation(UploadError) + ': ' + #13#10 + ErrText, False, mtError)
else
msgDlg(GetTranslation(ConnectionError, [URL, E.ErrorCode, GetTranslation(E.Message)]), False, mtError);
end;
end);
end;
procedure SetupProxy(var httpCli: TSslHttpCli);
begin
with httpCli do
begin
// Reset SOCKS
SocksServer := '';
SocksPort := '';
SocksAuthentication := socksNoAuthentication;
SocksUsercode := '';
SocksPassword := '';
// Reset HTTPS
Proxy := '';
ProxyPort := '';
ProxyUsername := '';
ProxyPassword := '';
ProxyAuth := OverbyteIcsHttpProt.httpAuthNone;
SslContext := SslCtx; // always define in case of a redirect to https
ProxyConnection := 'keep-alive';
if (MainProxy.proto in [PP_SOCKS4, PP_SOCKS5, PP_HTTPS]) then
case MainProxy.proto of
PP_SOCKS4, PP_SOCKS5:
begin
// sock.socksServer:=proxy.addr[proxy.proto].host;
// sock.socksPort:=proxy.addr[proxy.proto].port;
SocksServer := MainProxy.addr.host;
SocksPort := IntToStr(MainProxy.addr.port);
if MainProxy.proto = PP_SOCKS4 then
SocksLevel := '4'
else
SocksLevel := '5';
if MainProxy.auth then
SocksAuthentication := socksAuthenticateUsercode
else
SocksAuthentication := socksNoAuthentication;
SocksUsercode := MainProxy.user;
SocksPassword := MainProxy.pwd;
end;
PP_HTTPS:
begin
Proxy := MainProxy.addr.host;
ProxyPort := intToStr(MainProxy.addr.port);
// ProxyConnection - keep-alive?
if MainProxy.auth then
begin
ProxyUsername := MainProxy.user;
ProxyPassword := MainProxy.pwd;
if MainProxy.NTLM then
ProxyAuth := OverbyteIcsHttpProt.httpAuthNtlm
else
ProxyAuth := OverbyteIcsHttpProt.httpAuthBasic;
end else
ProxyAuth := OverbyteIcsHttpProt.httpAuthNone;
end
end;
end;
end;
function LoadFromURLAsString(const URL: String; var str: String; const POSTData: RawByteString = ''): Boolean;
var
fs: TMemoryStream;
begin
fs := nil;
str := '';
Result := LoadFromURL(URL, str, fs, 0, False, POSTData, True, True);
end;
function LoadFromURL(const URL: String; var fn: String; Threshold: LongInt = 0; ExtByContent: Boolean = False;
const POSTData: RawByteString = ''; ShowErrors: Boolean = True): Boolean;
var
fs: TMemoryStream;
begin
fs := nil;
Result := LoadFromURL(URL, fn, fs, Threshold, ExtByContent, POSTData, ShowErrors);
end;
function LoadFromURL(const URL: String; var fs: TMemoryStream; Threshold: LongInt = 0; ExtByContent: Boolean = False;
const POSTData: RawByteString = ''; ShowErrors: Boolean = True): Boolean;
var
fn: String;
begin
Result := LoadFromURL(URL, fn, fs, Threshold, ExtByContent, POSTData, ShowErrors);
end;
function LoadFromURL(const URL: String; var fn: String; var fs: TMemoryStream; Threshold: LongInt = 0;
ExtByContent: Boolean = False; const POSTData: RawByteString = ''; ShowErrors: Boolean = True; OutputAsStr: Boolean = False): Boolean;
var
AvStream: TStringStream;
httpCli: TSslHttpCli;
ft: TPAFormat;
begin
Result := False;
httpCli := TSslHttpCli.Create(nil);
try
httpCli.MultiThreaded := True;
httpCli.URL := URL;
httpCli.FollowRelocation := True;
httpCli.Connection := 'keep-alive';
// httpCli.Agent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/72.0';
SetupProxy(httpCli);
AvStream := TStringStream.Create('', TEncoding.UTF8);
httpCli.RcvdStream := AvStream;
try
if Threshold > 0 then
begin
httpCli.Head;
if httpCli.ContentLength > Threshold then
Exit;
end;
try
if not (POSTData = '') then
begin
httpCli.ContentTypePost := 'application/x-www-form-urlencoded';
httpCli.SendStream := TMemoryStream.Create;
httpCli.SendStream.Write(POSTData[1], Length(POSTData));
httpCli.SendStream.Seek(0, soFromBeginning);
httpCli.Post;
end else
httpCli.Get;
Result := True;
except
on E: EHttpException do
if ShowErrors then
HandleError(E, URL, '', False);
end;
if Result then
begin
AvStream.Seek(0, soFromBeginning);
if OutputAsStr then
fn := AvStream.DataString
else if not (fs = nil) then
begin
AvStream.SaveToStream(fs);
fs.Seek(0, soFromBeginning);
end
else if not (fn = '') then
begin
if ExtByContent then
begin
ft := DetectFileFormatStream(AvStream);
if ft <> PA_FORMAT_UNK then
fn := ChangeFileExt(fn, PAFormat[ft]);
end;
AvStream.SaveToFile(fn);
end;
end;
finally
FreeAndNil(AvStream);
end;
finally
if Assigned(httpCli.SendStream) then
httpCli.SendStream.Free;
httpCli.Free;
end;
end;
function LoadFromURLAsync(const URL: String; Callback: THttpRequestDone = nil; Data: Pointer = nil; const POSTData: RawByteString = ''; ShowErrors: Boolean = True): Boolean;
var
AvStream: TStringStream;
httpCli: TICQAsync;
begin
Result := False;
try
httpCli := TICQAsync.Create(nil);
httpCli.MultiThreaded := True;
httpCli.URL := URL;
httpCli.Contact := Data;
httpCli.FollowRelocation := True;
httpCli.Connection := 'keep-alive';
// httpCli.Agent := 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0';
SetupProxy(TSslHttpCli(httpCli));
AvStream := TStringStream.Create('', TEncoding.UTF8);
httpCli.RcvdStream := AvStream;
httpCli.OnRequestDone := Callback;
try
if not (POSTData = '') then
begin
httpCli.ContentTypePost := 'application/x-www-form-urlencoded';
httpCli.SendStream := TMemoryStream.Create;
httpCli.SendStream.Write(POSTData[1], Length(POSTData));
httpCli.SendStream.Seek(0, soFromBeginning);
httpCli.PostAsync;
end else
httpCli.GetAsync;
Result := True;
except
on E: EHttpException do
if ShowErrors then
HandleError(E, URL);
end;
except end;
end;
function HeaderFromURL(const URL: String): String;
var
AvStream: TMemoryStream;
httpCli: TSslHttpCli;
begin
Result := '';
if URL = '' then
Exit;
AvStream := TMemoryStream.Create;
httpCli := TSslHttpCli.Create(nil);
try
httpCli.MultiThreaded := True;
httpCli.URL := URL;
httpCli.FollowRelocation := True;
httpCli.Timeout := 2;
SetupProxy(httpCli);
httpCli.RcvdStream := AvStream;
try httpCli.Head; except end;
Result := httpCli.ContentType;
finally
httpCli.Free;
FreeAndNil(AvStream);
end;
end;
function FileSize(const aFilename: String): Int64;
var
info: TWin32FileAttributeData;
begin
result := -1;
if not GetFileAttributesEx(PWideChar(aFileName), GetFileExInfoStandard, @info) then
Exit;
result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
end;
function InputText(const Boundry, Name, Value: RawByteString): RawByteString;
begin
Result := '--' + boundry + CRLF + 'Content-Disposition: form-data; name="' + name + '"' + CRLF + CRLF + value + CRLF;
end;
function UploadFileRGhost(FileStream: TStream; const FileName: String; UploadCallbacks: TCallbacks): String;
var
AvStream, TokenStream: TMemoryStream;
httpCli: TSslHttpCli;
Host, Token, Buf, Boundry, TokenStr, FilePage: RawByteString;
JSONObject: TJSONObject;
i, p, ULimit: Integer;
Cookie, DirectLink: String;
begin
Result := '';
Boundry := 'RghostUploadBoundaryabcdef0123456789';
httpCli := TSslHttpCli.Create(nil);
try
TokenStream := TMemoryStream.Create;
httpCli.RcvdStream := TokenStream;
httpCli.BandwidthLimit := 0;
httpCli.RequestVer := '1.1';
httpCli.Connection := 'Keep-Alive';
httpCli.Reference := 'http://rghost.net/';
httpCli.Agent := 'rgup 1.3';
httpCli.URL := 'http://rghost.net/multiple/upload_host';
httpCli.Cookie := '';
SetupProxy(httpCli);
httpCli.Get;
for i := 0 to httpCli.RcvdHeader.Count - 1 do
if StartsText('Set-Cookie:', httpCli.RcvdHeader[i]) then
Cookie := StrUtils.ReplaceText(Copy(httpCli.RcvdHeader[i], 1, Pos(';', httpCli.RcvdHeader[i]) - 1), 'Set-Cookie: ', '');
TokenStream.Seek(0, soFromBeginning);
SetLength(TokenStr, TokenStream.Size);
TokenStream.ReadBuffer(TokenStr[1], TokenStream.Size);
TokenStream.Clear;
FreeAndNil(TokenStream);
except end;
JSONObject := TJSONObject.ParseJSONValue(TokenStr) as TJSONObject;
if Assigned(JSONObject) then
begin
Host := JSONObject.GetValue('upload_host').Value;
Token := JSONObject.GetValue('authenticity_token').Value;
ULimit := 100;
TryStrToInt(JSONObject.GetValue('upload_limit').Value, ULimit);
if FileSize(FileName) > ULimit * 1024 * 1024 then
begin
msgDlg(getTranslation(FileTooBig, [IntToStr(ULimit)]), true, mtError);
httpCli.Free;
Exit;
end;
end
else
begin
msgDlg(getTranslation(AuthFailed), true, mtError);
httpCli.Free;
Exit;
end;
AvStream := TMemoryStream.Create;
try
httpCli.URL := 'http://' + Host + '/files';
httpCli.ContentTypePost := 'multipart/form-data; boundary=' + Boundry;
httpCli.SendStream := TMemoryStream.Create;
Buf := InputText(Boundry, 'authenticity_token', Token) +
'--' + Boundry + CRLF + 'Content-Disposition: form-data; name="file"; filename="' + UTF(FileName) + '"' + CRLF +
'Content-Transfer-Encoding: binary' + CRLF + CRLF;
httpCli.SendStream.Write(Buf[1], Length(Buf));
httpCli.SendStream.CopyFrom(FileStream, 0);
Buf := CRLF + '--' + Boundry + '--' + CRLF;
httpCli.SendStream.Write(Buf[1], Length(Buf));
httpCli.SendStream.Seek(0, soFromBeginning);
httpCli.OnBeforeHeaderSend := UploadCallbacks.OnBeforeHeaderSend;
httpCli.OnSendData := UploadCallbacks.OnSendData;
httpCli.RcvdStream := AvStream;
httpCli.Cookie := Cookie;
try
UploadSize := httpCli.SendStream.Size;
UploadedSize := 0;
IsUploading := True;
httpCli.FollowRelocation := False;
httpCli.Post;
IsUploading := False;
for i := 0 to httpCli.RcvdHeader.Count - 1 do
if StartsText('Location:', httpCli.RcvdHeader[i]) then
Result := Trim(StrUtils.ReplaceText(httpCli.RcvdHeader[i], 'Location:', ''));
if not (Result = '') then
begin
AvStream.Clear;
httpCli.URL := Result;
httpCli.FollowRelocation := True;
httpCli.Get;
AvStream.Seek(0, soFromBeginning);
SetLength(FilePage, AvStream.Size);
AvStream.ReadBuffer(FilePage[1], AvStream.Size);
p := Pos('name="file[direct_link]" onclick="this.select();" size="30" title="', FilePage) + 67;
DirectLink := Copy(FilePage, p, Pos('"', FilePage, p) - p);
//ODS(DirectLink);
if StartsText('http://', DirectLink) then
Result := DirectLink;
end;
except
msgDlg(getTranslation(UploadError) + ': ' + httpCli.LastResponse, true, mtError);
end;
finally
IsUploading := False;
if Assigned(httpCli.SendStream) then
httpCli.SendStream.Free;
httpCli.Free;
if Assigned(AvStream) then
FreeAndNil(AvStream);
end;
end;
function UploadFile2MyServer(FileStream: TStream; const fn: String; const Boundry: RawByteString; const URL: String; UploadCallbacks: TCallbacks): String;
var
AvStream: TMemoryStream;
httpCli: TSslHttpCli;
Buf, UploadedName: RawByteString;
begin
Result := '';
httpCli := TSslHttpCli.Create(nil);
httpCli.BandwidthLimit := 0;
httpCli.RequestVer := '1.1';
httpCli.Connection := 'Keep-Alive';
httpCli.Agent := 'R&Q';
if FileStream.Size > 100 * 1024 * 1024 then
begin
msgDlg(getTranslation(FileTooBig, [IntToStr(100)]), true, mtError);
httpCli.Free;
Exit;
end;
AvStream := TMemoryStream.Create;
try
httpCli.URL := URL;
SetupProxy(httpCli);
httpCli.ContentTypePost := 'multipart/form-data; boundary=' + Boundry;
httpCli.SendStream := TMemoryStream.Create;
Buf := InputText(Boundry, 'fname', UTF(fn)) +
'--' + Boundry + CRLF + 'Content-Disposition: form-data; name="file"; filename="' + UTF(fn) + '"' + CRLF +
'Content-Transfer-Encoding: binary' + CRLF + CRLF;
httpCli.SendStream.Write(Buf[1], Length(Buf));
httpCli.SendStream.CopyFrom(FileStream, 0);
Buf := CRLF + '--' + Boundry + '--' + CRLF;
httpCli.SendStream.Write(Buf[1], Length(Buf));
httpCli.SendStream.Seek(0, soFromBeginning);
httpCli.OnBeforeHeaderSend := UploadCallbacks.OnBeforeHeaderSend;
httpCli.OnSendData := UploadCallbacks.OnSendData;
httpCli.RcvdStream := AvStream;
try
UploadSize := httpCli.SendStream.Size;
UploadedSize := 0;
IsUploading := True;
httpCli.FollowRelocation := False;
httpCli.Post;
IsUploading := False;
AvStream.Seek(0, soFromBeginning);
SetLength(UploadedName, AvStream.Size);
AvStream.ReadBuffer(UploadedName[1], AvStream.Size);
Result := LowerCase(UploadedName);
except
on E: EHttpException do
HandleError(E, URL, httpCli.RcvdHeader.Text, False);
end;
finally
IsUploading := False;
if Assigned(httpCli.SendStream) then
httpCli.SendStream.Free;
httpCli.Free;
if Assigned(AvStream) then
FreeAndNil(AvStream);
end;
end;
function UploadFileRnQ(FileStream: TStream; const FileName: String; UploadCallbacks: TCallbacks): String;
begin
Result := UploadFile2MyServer(FileStream, FileName, '---------------RnQPortalServerUpload', 'https://rnq.ru/file_upload.php', UploadCallbacks);
end;
function UploadFileMikanoshi(FileStream: TStream; const FileName: String; UploadCallbacks: TCallbacks): String;
begin
Result := UploadFile2MyServer(FileStream, FileName, '---------------MikanoshiServerUpload', 'https://code.highspec.ru/upload.php', UploadCallbacks);
end;
function GetICQFileLinkInfo(const lnk: String): TICQFileInfo;
var
JSONObject: TJSONObject;
fileIdStr, imgStr: RawByteString;
buf: TMemoryStream;
fn: String;
begin
Result := Default(TICQFileInfo);
fileIdStr := ReplaceText(Trim(lnk), 'files.icq.net/get/', 'files.icq.com/getinfo?file_id=');
fileIdStr := ReplaceText(fileIdStr, 'files.icq.net/files/get?fileId=', 'files.icq.com/getinfo?file_id=');
Result.jsonlink := fileIdStr;
buf := TMemoryStream.Create;
LoadFromURL(fileIdStr, fn, buf, 0, False, '', False);
SetLength(imgStr, buf.Size);
buf.ReadBuffer(imgStr[1], buf.Size);
buf.Free;
JSONObject := TJSONObject.ParseJSONValue(imgStr) as TJSONObject;
if Assigned(JSONObject) then
try
JSONObject := TJSONObject.ParseJSONValue(TJSONArray(JSONObject.GetValue('file_list')).Items[0].ToJSON) as TJSONObject;
Result.dlink := JSONObject.GetValue('dlink').Value;
Result.mime := JSONObject.GetValue('mime').Value;
Result.filename := JSONObject.GetValue('filename').Value;
Result.is_previewable := StrToInt(JSONObject.GetValue('is_previewable').Value) = 1;
if Result.is_previewable then
if Result.filename.startsWith('dnld') then // sticker?
Result.preview := JSONObject.GetValue('static').Value
else
Result.preview := JSONObject.GetValue('xlarge').Value;
JSONObject.Free;
except end;
end;
function CheckType(const lnk: String): Boolean;
var
ext: String;
sA: RawByteString;
begin
Result := CheckType(lnk, sA, ext);
end;
function CheckType(const lnk: String; var sA: RawByteString; var ext: String): Boolean;
var
Task: ITask;
Res, HasMime: Boolean;
sALocal: RawByteString;
extLocal, anchor: String;
info: TICQFileInfo;
begin
Res := False;
HasMime := False;
Task := TTask.Run(procedure()
var
buf: TMemoryStream;
idx: Integer;
ctype, fn: String;
imgStr: RawByteString;
begin
if EnableVideoLinks and (ContainsText(lnk, 'youtube.com/') or ContainsText(lnk, 'youtu.be/') or ContainsText(lnk, 'vimeo.com/')) then
begin
buf := TMemoryStream.Create;
LoadFromURL(lnk, fn, buf, 0, False, '', False);
SetLength(imgStr, buf.Size);
buf.ReadBuffer(imgStr[1], buf.Size);
buf.Free;
anchor := 'property="og:image" content="';
sALocal := copy(imgStr, pos(anchor, imgStr) + length(anchor));
sALocal := copy(sALocal, 1, pos('"', sALocal) - 1);
sALocal := DecodeURL(UnUTF(sALocal));
end else if ContainsText(lnk, 'files.icq.net/') then
begin
info := GetICQFileLinkInfo(lnk);
if info.mime.startsWith('image/') then
begin
if info.preview = '' then
sALocal := info.dlink
else if info.is_previewable then
sALocal := info.preview;
ctype := info.mime;
HasMime := True;
end else if info.is_previewable then
begin
sALocal := info.preview;
ctype := info.mime;
HasMime := True;
end else
sALocal := '';
end else
sALocal := Trim(lnk);
if not HasMime then
ctype := HeaderFromURL(sALocal);
if not (ctype = '') and (pos(';', ctype) > 0) then
ctype := copy(ctype, 1, pos(';', ctype) - 1);
CacheType(lnk, ctype);
if MatchText(ctype, ImageContentTypes) then
begin
Res := True;
idx := IndexText(ctype, ImageContentTypes);
if idx >= 0 then
extLocal := ImageExtensions[idx]
else
extLocal := 'jpg';
end;
end);
task.Wait(10000);
sA := sALocal;
ext := extLocal;
Result := Res;
end;
function DownloadAndCache(const lnk: String): Boolean;
var
ext: String;
sA: RawByteString;
res: Boolean;
buf: TMemoryStream;
begin
Result := False;
if not CheckType(lnk, sA, ext) then
Exit;
buf := TMemoryStream.Create;
LoadFromURL(sA, buf, 0, False, '', False);
TThread.Synchronize(nil, procedure begin
if buf.Size = 0 then
CacheType(lnk, 'text/html')
else
res := CacheImage(buf, lnk, ext);
end);
if Assigned(buf) then
buf.Free;
Result := res;
end;
function CreateZip(str: TStringList): TMemoryStream;
var
Zip: TZipFile;
i: Integer;
fs: TFileStream;
pData: RawByteString;
begin
Result := TMemoryStream.Create;
Zip := TZipFile.Create;
try
for i := 0 to str.Count - 1 do
if FileExists(str.Strings[i]) then
begin
fs := TFileStream.Create(str.Strings[i], fmOpenRead);
SetLength(pData, fs.Size);
fs.ReadBuffer(pData[1], fs.Size);
FreeAndNil(fs);
Zip.AddFile(ExtractFileName(str.Strings[i]), 0, '', pData);
end;
Zip.SaveToStream(Result);
except end;
FreeAndNil(Zip);
end;
initialization
SslCtx := TSslContext.Create(nil);
finalization
FreeAndNil(SslCtx);
// ClearProxyArr(AllProxies);
end.