mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-08-04 06:51:50 +02:00
SMB1 helpers: Improved code readability
This commit is contained in:
parent
30f0a641d2
commit
ce96106b5b
7 changed files with 51 additions and 51 deletions
|
@ -21,7 +21,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!share.HasWriteAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
|
@ -33,13 +33,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Debug, "CreateDirectory: Cannot create '{0}'", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_INVALID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "CreateDirectory: Cannot create '{0}', Access Denied", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
return new CreateDirectoryResponse();
|
||||
|
@ -51,7 +51,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!share.HasWriteAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
|
@ -59,13 +59,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (entry == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -77,13 +77,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}'", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_CANNOT_DELETE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}', Access Denied", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (entry == null || !entry.IsDirectory)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_CHECK_DIRECTORY);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
return new CheckDirectoryResponse();
|
||||
|
@ -106,7 +106,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!share.HasWriteAccess(session.UserName, request.FileName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
|
@ -114,14 +114,14 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (entry == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) > 0
|
||||
|| entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) == 0)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -133,13 +133,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Debug, "Delete: Cannot delete '{0}'", request.FileName);
|
||||
header.Status = NTStatus.STATUS_CANNOT_DELETE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}', Access Denied", request.FileName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,12 +149,12 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!share.HasWriteAccess(session.UserName, request.OldFileName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (!share.HasWriteAccess(session.UserName, request.NewFileName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
|
@ -162,7 +162,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (sourceEntry == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
// The file must not already exist unless we just want to upcase / downcase a filename letter
|
||||
|
@ -172,7 +172,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
// The new file already exists.
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -184,13 +184,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Debug, "Rename: Sharing violation renaming '{0}'", request.OldFileName);
|
||||
header.Status = NTStatus.STATUS_SHARING_VIOLATION;
|
||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "Rename: Cannot rename '{0}', Access Denied", request.OldFileName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (entry == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_QUERY_INFORMATION);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
QueryInformationResponse response = new QueryInformationResponse();
|
||||
|
@ -218,7 +218,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!share.HasWriteAccess(session.UserName, request.FileName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
|
@ -226,7 +226,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (entry == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
bool? isHidden = null;
|
||||
|
@ -261,13 +261,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (openFile == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_SMB_BAD_FID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!share.HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!fileID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (isExtended)
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
|
@ -60,7 +60,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = createStatus;
|
||||
return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
FileAccess fileAccess = NTFileSystemHelper.ToFileAccess(request.DesiredAccess);
|
||||
|
@ -85,7 +85,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = openStatus;
|
||||
return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!fileID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (isExtended)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!fileID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (isExtended)
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
else if (request.OpenMode.FileExistsOpts == FileExistsOpts.TruncateToZero)
|
||||
{
|
||||
|
@ -79,18 +79,18 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_SHARING_VIOLATION;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
else
|
||||
{
|
||||
header.Status = NTStatus.STATUS_DATA_ERROR;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
openResult = OpenResult.FileExistedAndWasTruncated;
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (request.OpenMode.CreateFile == CreateFile.ReturnErrorIfNotExist)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if ((request.FileAttrs & SMBFileAttributes.Directory) > 0)
|
||||
|
@ -136,7 +136,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!fileID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (isExtended)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (openFile == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_SMB_BAD_FID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_CLOSE);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
state.LogToServer(Severity.Verbose, "Close: Closing file '{0}'", openFile.Path);
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Information, "User '{0}' authentication using an empty password was rejected", message.UserName);
|
||||
header.Status = NTStatus.STATUS_ACCOUNT_RESTRICTION;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (loginSuccess)
|
||||
|
@ -44,7 +44,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (session == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
header.UID = session.UserID;
|
||||
response.PrimaryDomain = request.PrimaryDomain;
|
||||
|
@ -56,7 +56,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (session == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
header.UID = session.UserID;
|
||||
response.Action = SessionSetupAction.SetupGuest;
|
||||
|
@ -66,7 +66,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Information, "User '{0}' failed authentication", message.UserName);
|
||||
header.Status = NTStatus.STATUS_LOGON_FAILURE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if ((request.Capabilities & ServerCapabilities.LargeRead) > 0)
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
// According to [MS-SMB] 3.3.5.3, a UID MUST be allocated if the server returns STATUS_MORE_PROCESSING_REQUIRED
|
||||
|
@ -139,7 +139,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Information, "User '{0}' authentication using an empty password was rejected", authenticateMessage.UserName);
|
||||
header.Status = NTStatus.STATUS_ACCOUNT_RESTRICTION;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (loginSuccess)
|
||||
|
@ -157,7 +157,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
state.LogToServer(Severity.Information, "User '{0}' failed authentication", authenticateMessage.UserName);
|
||||
header.Status = NTStatus.STATUS_LOGON_FAILURE;
|
||||
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!isRawMessage)
|
||||
|
|
|
@ -33,20 +33,20 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (share == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!((FileSystemShare)share).HasReadAccess(session.UserName, @"\", state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
ushort? treeID = session.AddConnectedTree(share);
|
||||
if (!treeID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_INSUFF_SERVER_RESOURCES;
|
||||
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
header.TID = treeID.Value;
|
||||
if (isExtended)
|
||||
|
@ -92,7 +92,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (!session.IsTreeConnected(header.TID))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_SMB_BAD_TID;
|
||||
return new ErrorResponse(CommandName.SMB_COM_TREE_DISCONNECT);
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
session.RemoveConnectedTree(header.TID);
|
||||
|
|
|
@ -252,7 +252,7 @@ namespace SMBLibrary.Server
|
|||
else if (command is LockingAndXRequest)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(CommandName.SMB_COM_LOCKING_ANDX);
|
||||
return new ErrorResponse(command.CommandName);
|
||||
}
|
||||
else if (command is OpenAndXRequest)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue