mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-12-27 08:19:30 +08:00
Use upstream defined namespace
`lt` namespace is defined since libtorrent 1.1.6 and our master branch requires >= 1.1.10, so there is no need to add #if condition for it.
This commit is contained in:
parent
6d73a7ef0a
commit
677a419f0b
@ -56,7 +56,6 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
MagnetUri::MagnetUri(const QString &source)
|
||||
@ -68,8 +67,8 @@ MagnetUri::MagnetUri(const QString &source)
|
||||
if (isBitTorrentInfoHash(source))
|
||||
m_url = QLatin1String("magnet:?xt=urn:btih:") + source;
|
||||
|
||||
libt::error_code ec;
|
||||
libt::parse_magnet_uri(m_url.toStdString(), m_addTorrentParams, ec);
|
||||
lt::error_code ec;
|
||||
lt::parse_magnet_uri(m_url.toStdString(), m_addTorrentParams, ec);
|
||||
if (ec) return;
|
||||
|
||||
m_valid = true;
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "base/unicodestrings.h"
|
||||
#include "base/utils/string.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
// PeerAddress
|
||||
@ -51,7 +50,7 @@ PeerAddress::PeerAddress(const QHostAddress &ip, ushort port)
|
||||
|
||||
// PeerInfo
|
||||
|
||||
PeerInfo::PeerInfo(const TorrentHandle *torrent, const libt::peer_info &nativeInfo)
|
||||
PeerInfo::PeerInfo(const TorrentHandle *torrent, const lt::peer_info &nativeInfo)
|
||||
: m_nativeInfo(nativeInfo)
|
||||
{
|
||||
calcRelevance(torrent);
|
||||
@ -60,17 +59,17 @@ PeerInfo::PeerInfo(const TorrentHandle *torrent, const libt::peer_info &nativeIn
|
||||
|
||||
bool PeerInfo::fromDHT() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.source & libt::peer_info::dht);
|
||||
return static_cast<bool>(m_nativeInfo.source & lt::peer_info::dht);
|
||||
}
|
||||
|
||||
bool PeerInfo::fromPeX() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.source & libt::peer_info::pex);
|
||||
return static_cast<bool>(m_nativeInfo.source & lt::peer_info::pex);
|
||||
}
|
||||
|
||||
bool PeerInfo::fromLSD() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.source & libt::peer_info::lsd);
|
||||
return static_cast<bool>(m_nativeInfo.source & lt::peer_info::lsd);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
@ -82,102 +81,102 @@ QString PeerInfo::country() const
|
||||
|
||||
bool PeerInfo::isInteresting() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::interesting);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::interesting);
|
||||
}
|
||||
|
||||
bool PeerInfo::isChocked() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::choked);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::choked);
|
||||
}
|
||||
|
||||
bool PeerInfo::isRemoteInterested() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::remote_interested);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::remote_interested);
|
||||
}
|
||||
|
||||
bool PeerInfo::isRemoteChocked() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::remote_choked);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::remote_choked);
|
||||
}
|
||||
|
||||
bool PeerInfo::isSupportsExtensions() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::supports_extensions);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::supports_extensions);
|
||||
}
|
||||
|
||||
bool PeerInfo::isLocalConnection() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::local_connection);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::local_connection);
|
||||
}
|
||||
|
||||
bool PeerInfo::isHandshake() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::handshake);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::handshake);
|
||||
}
|
||||
|
||||
bool PeerInfo::isConnecting() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::connecting);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::connecting);
|
||||
}
|
||||
|
||||
bool PeerInfo::isOnParole() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::on_parole);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::on_parole);
|
||||
}
|
||||
|
||||
bool PeerInfo::isSeed() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::seed);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::seed);
|
||||
}
|
||||
|
||||
bool PeerInfo::optimisticUnchoke() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::optimistic_unchoke);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::optimistic_unchoke);
|
||||
}
|
||||
|
||||
bool PeerInfo::isSnubbed() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::snubbed);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::snubbed);
|
||||
}
|
||||
|
||||
bool PeerInfo::isUploadOnly() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::upload_only);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::upload_only);
|
||||
}
|
||||
|
||||
bool PeerInfo::isEndgameMode() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::endgame_mode);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::endgame_mode);
|
||||
}
|
||||
|
||||
bool PeerInfo::isHolepunched() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::holepunched);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::holepunched);
|
||||
}
|
||||
|
||||
bool PeerInfo::useI2PSocket() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::i2p_socket);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::i2p_socket);
|
||||
}
|
||||
|
||||
bool PeerInfo::useUTPSocket() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::utp_socket);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::utp_socket);
|
||||
}
|
||||
|
||||
bool PeerInfo::useSSLSocket() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::ssl_socket);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::ssl_socket);
|
||||
}
|
||||
|
||||
bool PeerInfo::isRC4Encrypted() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::rc4_encrypted);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::rc4_encrypted);
|
||||
}
|
||||
|
||||
bool PeerInfo::isPlaintextEncrypted() const
|
||||
{
|
||||
return static_cast<bool>(m_nativeInfo.flags & libt::peer_info::plaintext_encrypted);
|
||||
return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::plaintext_encrypted);
|
||||
}
|
||||
|
||||
PeerAddress PeerInfo::address() const
|
||||
@ -229,13 +228,13 @@ QBitArray PeerInfo::pieces() const
|
||||
|
||||
QString PeerInfo::connectionType() const
|
||||
{
|
||||
if (m_nativeInfo.flags & libt::peer_info::utp_socket)
|
||||
if (m_nativeInfo.flags & lt::peer_info::utp_socket)
|
||||
return QString::fromUtf8(C_UTP);
|
||||
|
||||
QString connection;
|
||||
switch (m_nativeInfo.connection_type) {
|
||||
case libt::peer_info::http_seed:
|
||||
case libt::peer_info::web_seed:
|
||||
case lt::peer_info::http_seed:
|
||||
case lt::peer_info::web_seed:
|
||||
connection = "Web";
|
||||
break;
|
||||
default:
|
||||
|
@ -35,8 +35,6 @@
|
||||
|
||||
#include "base/logger.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
|
||||
namespace
|
||||
{
|
||||
class IPv4Parser
|
||||
@ -79,24 +77,24 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
libt::address_v4::bytes_type parsed() const
|
||||
lt::address_v4::bytes_type parsed() const
|
||||
{
|
||||
return m_buf;
|
||||
}
|
||||
|
||||
private:
|
||||
libt::address_v4::bytes_type m_buf;
|
||||
lt::address_v4::bytes_type m_buf;
|
||||
};
|
||||
|
||||
bool parseIPAddress(const char *data, libt::address &address)
|
||||
bool parseIPAddress(const char *data, lt::address &address)
|
||||
{
|
||||
IPv4Parser parser;
|
||||
boost::system::error_code ec;
|
||||
|
||||
if (parser.tryParse(data))
|
||||
address = libt::address_v4(parser.parsed());
|
||||
address = lt::address_v4(parser.parsed());
|
||||
else
|
||||
address = libt::address_v6::from_string(data, ec);
|
||||
address = lt::address_v6::from_string(data, ec);
|
||||
|
||||
return !ec;
|
||||
}
|
||||
@ -214,7 +212,7 @@ int FilterParserThread::parseDATFilterFile()
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address startAddr;
|
||||
lt::address startAddr;
|
||||
int newStart = trim(buffer.data(), start, delimIP - 1);
|
||||
if (!parseIPAddress(buffer.data() + newStart, startAddr)) {
|
||||
++parseErrorCount;
|
||||
@ -223,7 +221,7 @@ int FilterParserThread::parseDATFilterFile()
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address endAddr;
|
||||
lt::address endAddr;
|
||||
newStart = trim(buffer.data(), delimIP + 1, endOfIPRange);
|
||||
if (!parseIPAddress(buffer.data() + newStart, endAddr)) {
|
||||
++parseErrorCount;
|
||||
@ -244,7 +242,7 @@ int FilterParserThread::parseDATFilterFile()
|
||||
|
||||
// Now Add to the filter
|
||||
try {
|
||||
m_filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
|
||||
m_filter.add_rule(startAddr, endAddr, lt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
@ -353,7 +351,7 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address startAddr;
|
||||
lt::address startAddr;
|
||||
int newStart = trim(buffer.data(), partsDelimiter + 1, delimIP - 1);
|
||||
if (!parseIPAddress(buffer.data() + newStart, startAddr)) {
|
||||
++parseErrorCount;
|
||||
@ -362,7 +360,7 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address endAddr;
|
||||
lt::address endAddr;
|
||||
newStart = trim(buffer.data(), delimIP + 1, endOfLine);
|
||||
if (!parseIPAddress(buffer.data() + newStart, endAddr)) {
|
||||
++parseErrorCount;
|
||||
@ -382,7 +380,7 @@ int FilterParserThread::parseP2PFilterFile()
|
||||
start = endOfLine;
|
||||
|
||||
try {
|
||||
m_filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
|
||||
m_filter.add_rule(startAddr, endAddr, lt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
@ -463,11 +461,11 @@ int FilterParserThread::parseP2BFilterFile()
|
||||
// Network byte order to Host byte order
|
||||
// asio address_v4 constructor expects it
|
||||
// that way
|
||||
const libt::address_v4 first(ntohl(start));
|
||||
const libt::address_v4 last(ntohl(end));
|
||||
const lt::address_v4 first(ntohl(start));
|
||||
const lt::address_v4 last(ntohl(end));
|
||||
// Apply to bittorrent session
|
||||
try {
|
||||
m_filter.add_rule(first, last, libt::ip_filter::blocked);
|
||||
m_filter.add_rule(first, last, lt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch (std::exception &) {}
|
||||
@ -513,11 +511,11 @@ int FilterParserThread::parseP2BFilterFile()
|
||||
// Network byte order to Host byte order
|
||||
// asio address_v4 constructor expects it
|
||||
// that way
|
||||
const libt::address_v4 first(ntohl(start));
|
||||
const libt::address_v4 last(ntohl(end));
|
||||
const lt::address_v4 first(ntohl(start));
|
||||
const lt::address_v4 last(ntohl(end));
|
||||
// Apply to bittorrent session
|
||||
try {
|
||||
m_filter.add_rule(first, last, libt::ip_filter::blocked);
|
||||
m_filter.add_rule(first, last, lt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch (std::exception &) {}
|
||||
@ -547,12 +545,12 @@ void FilterParserThread::processFilterFile(const QString &filePath)
|
||||
|
||||
m_abort = false;
|
||||
m_filePath = filePath;
|
||||
m_filter = libt::ip_filter();
|
||||
m_filter = lt::ip_filter();
|
||||
// Run it
|
||||
start();
|
||||
}
|
||||
|
||||
libt::ip_filter FilterParserThread::IPfilter()
|
||||
lt::ip_filter FilterParserThread::IPfilter()
|
||||
{
|
||||
return m_filter;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -62,7 +62,6 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
TorrentCreatorThread::TorrentCreatorThread(QObject *parent)
|
||||
@ -97,9 +96,9 @@ void TorrentCreatorThread::run()
|
||||
const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + '/';
|
||||
|
||||
// Adding files to the torrent
|
||||
libt::file_storage fs;
|
||||
lt::file_storage fs;
|
||||
if (QFileInfo(m_params.inputPath).isFile()) {
|
||||
libt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter);
|
||||
lt::add_files(fs, Utils::Fs::toNativePath(m_params.inputPath).toStdString(), fileFilter);
|
||||
}
|
||||
else {
|
||||
// need to sort the file names by natural sort order
|
||||
@ -137,8 +136,8 @@ void TorrentCreatorThread::run()
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
libt::create_torrent newTorrent(fs, m_params.pieceSize, -1
|
||||
, (m_params.isAlignmentOptimized ? libt::create_torrent::optimize_alignment : CreateFlags {}));
|
||||
lt::create_torrent newTorrent(fs, m_params.pieceSize, -1
|
||||
, (m_params.isAlignmentOptimized ? lt::create_torrent::optimize_alignment : CreateFlags {}));
|
||||
|
||||
// Add url seeds
|
||||
for (QString seed : asConst(m_params.urlSeeds)) {
|
||||
@ -158,7 +157,7 @@ void TorrentCreatorThread::run()
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
// calculate the hash for all pieces
|
||||
libt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
|
||||
lt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
|
||||
, [this, &newTorrent](const int n) { sendProgressSignal(n, newTorrent.num_pieces()); });
|
||||
// Set qBittorrent as creator and add user comment to
|
||||
// torrent_info structure
|
||||
@ -169,7 +168,7 @@ void TorrentCreatorThread::run()
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
libt::entry entry = newTorrent.generate();
|
||||
lt::entry entry = newTorrent.generate();
|
||||
|
||||
// add source field
|
||||
if (!m_params.source.isEmpty())
|
||||
@ -190,7 +189,7 @@ void TorrentCreatorThread::run()
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
|
||||
libt::bencode(std::ostream_iterator<char>(outfile), entry);
|
||||
lt::bencode(std::ostream_iterator<char>(outfile), entry);
|
||||
outfile.close();
|
||||
|
||||
emit updateProgress(100);
|
||||
@ -206,9 +205,9 @@ int TorrentCreatorThread::calculateTotalPieces(const QString &inputPath, const i
|
||||
if (inputPath.isEmpty())
|
||||
return 0;
|
||||
|
||||
libt::file_storage fs;
|
||||
libt::add_files(fs, Utils::Fs::toNativePath(inputPath).toStdString(), fileFilter);
|
||||
lt::file_storage fs;
|
||||
lt::add_files(fs, Utils::Fs::toNativePath(inputPath).toStdString(), fileFilter);
|
||||
|
||||
return libt::create_torrent(fs, pieceSize, -1
|
||||
, (isAlignmentOptimized ? libt::create_torrent::optimize_alignment : CreateFlags {})).num_pieces();
|
||||
return lt::create_torrent(fs, pieceSize, -1
|
||||
, (isAlignmentOptimized ? lt::create_torrent::optimize_alignment : CreateFlags {})).num_pieces();
|
||||
}
|
||||
|
@ -59,15 +59,14 @@ namespace
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
TorrentInfo::TorrentInfo(NativeConstPtr nativeInfo)
|
||||
{
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
m_nativeInfo = boost::const_pointer_cast<libt::torrent_info>(nativeInfo);
|
||||
m_nativeInfo = boost::const_pointer_cast<lt::torrent_info>(nativeInfo);
|
||||
#else
|
||||
m_nativeInfo = std::const_pointer_cast<libt::torrent_info>(nativeInfo);
|
||||
m_nativeInfo = std::const_pointer_cast<lt::torrent_info>(nativeInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -88,9 +87,9 @@ TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept
|
||||
// used in `torrent_info()` constructor
|
||||
const int depthLimit = 100;
|
||||
const int tokenLimit = 10000000;
|
||||
libt::error_code ec;
|
||||
lt::error_code ec;
|
||||
|
||||
libt::bdecode_node node;
|
||||
lt::bdecode_node node;
|
||||
bdecode(data.constData(), (data.constData() + data.size()), node, ec
|
||||
, nullptr, depthLimit, tokenLimit);
|
||||
if (ec) {
|
||||
@ -99,7 +98,7 @@ TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept
|
||||
return TorrentInfo();
|
||||
}
|
||||
|
||||
TorrentInfo info {NativePtr(new libt::torrent_info(node, ec))};
|
||||
TorrentInfo info {NativePtr(new lt::torrent_info(node, ec))};
|
||||
if (ec) {
|
||||
if (error)
|
||||
*error = QString::fromStdString(ec.message());
|
||||
@ -270,7 +269,7 @@ QList<TrackerEntry> TorrentInfo::trackers() const
|
||||
if (!isValid()) return {};
|
||||
|
||||
QList<TrackerEntry> trackers;
|
||||
for (const libt::announce_entry &tracker : m_nativeInfo->trackers())
|
||||
for (const lt::announce_entry &tracker : m_nativeInfo->trackers())
|
||||
trackers.append(tracker);
|
||||
|
||||
return trackers;
|
||||
@ -281,8 +280,8 @@ QList<QUrl> TorrentInfo::urlSeeds() const
|
||||
if (!isValid()) return {};
|
||||
|
||||
QList<QUrl> urlSeeds;
|
||||
for (const libt::web_seed_entry &webSeed : m_nativeInfo->web_seeds())
|
||||
if (webSeed.type == libt::web_seed_entry::url_seed)
|
||||
for (const lt::web_seed_entry &webSeed : m_nativeInfo->web_seeds())
|
||||
if (webSeed.type == lt::web_seed_entry::url_seed)
|
||||
urlSeeds.append(QUrl(webSeed.url.c_str()));
|
||||
|
||||
return urlSeeds;
|
||||
@ -312,13 +311,13 @@ QVector<int> TorrentInfo::fileIndicesForPiece(const int pieceIndex) const
|
||||
if (!isValid() || (pieceIndex < 0) || (pieceIndex >= piecesCount()))
|
||||
return {};
|
||||
|
||||
const std::vector<libt::file_slice> files(
|
||||
const std::vector<lt::file_slice> files(
|
||||
nativeInfo()->map_block(LTPieceIndex {pieceIndex}, 0
|
||||
, nativeInfo()->piece_size(LTPieceIndex {pieceIndex})));
|
||||
QVector<int> res;
|
||||
res.reserve(int(files.size()));
|
||||
std::transform(files.begin(), files.end(), std::back_inserter(res),
|
||||
[](const libt::file_slice &s) { return static_cast<int>(s.file_index); });
|
||||
[](const lt::file_slice &s) { return static_cast<int>(s.file_index); });
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -361,7 +360,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
|
||||
return {};
|
||||
}
|
||||
|
||||
const libt::file_storage &files = nativeInfo()->files();
|
||||
const lt::file_storage &files = nativeInfo()->files();
|
||||
const auto fileSize = files.file_size(LTFileIndex {fileIndex});
|
||||
const auto fileOffset = files.file_offset(LTFileIndex {fileIndex});
|
||||
return makeInterval(static_cast<int>(fileOffset / pieceLength()),
|
||||
|
Loading…
Reference in New Issue
Block a user