added amb618 - binary file i/o
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401802
This commit is contained in:
		
							parent
							
								
									cf023a0b7d
								
							
						
					
					
						commit
						abb763d1e1
					
				@ -640,6 +640,197 @@ static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
 | 
				
			|||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Handle_t hndl = static_cast<Handle_t>(params[1]);
 | 
				
			||||||
 | 
						HandleError herr;
 | 
				
			||||||
 | 
						HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | 
				
			||||||
 | 
						FILE *pFile;
 | 
				
			||||||
 | 
						size_t read = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
 | 
				
			||||||
 | 
							!= HandleError_None)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (params[4] != 1 && params[4] != 2 && params[4] != 4)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell_t *data;
 | 
				
			||||||
 | 
						pContext->LocalToPhysAddr(params[2], &data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (params[4] == 4)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							read = fread(data, sizeof(cell_t), params[3], pFile);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (params[4] == 2)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int16_t val;
 | 
				
			||||||
 | 
							for (cell_t i = 0; i < params[3]; i++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (fread(&val, sizeof(int16_t), 1, pFile) != 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								data[read++] = val;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (params[4] == 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int8_t val;
 | 
				
			||||||
 | 
							for (cell_t i = 0; i < params[3]; i++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (fread(&val, sizeof(int8_t), 1, pFile) != 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								data[read++] = val;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (read != (size_t)params[3] && ferror(pFile) != 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return read;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Handle_t hndl = static_cast<Handle_t>(params[1]);
 | 
				
			||||||
 | 
						HandleError herr;
 | 
				
			||||||
 | 
						HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | 
				
			||||||
 | 
						FILE *pFile;
 | 
				
			||||||
 | 
						cell_t num_read = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
 | 
				
			||||||
 | 
							!= HandleError_None)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *buffer;
 | 
				
			||||||
 | 
						pContext->LocalToString(params[2], &buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char val;
 | 
				
			||||||
 | 
						while (1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* If we're in stop mode, break as soon as the buffer is full. */
 | 
				
			||||||
 | 
							if (params[4] && (params[3] == 0 || num_read >= params[3] - 1))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (fread(&val, sizeof(val), 1, pFile) != 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (ferror(pFile))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (val == '\0')
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (params[3] > 0 && num_read < params[3] - 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								buffer[num_read++] = val;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (params[3] > 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							buffer[num_read] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return num_read;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Handle_t hndl = static_cast<Handle_t>(params[1]);
 | 
				
			||||||
 | 
						HandleError herr;
 | 
				
			||||||
 | 
						HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | 
				
			||||||
 | 
						FILE *pFile;
 | 
				
			||||||
 | 
						size_t read = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
 | 
				
			||||||
 | 
							!= HandleError_None)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell_t *data;
 | 
				
			||||||
 | 
						pContext->LocalToPhysAddr(params[2], &data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (params[4] != 1 && params[4] != 2 && params[4] != 4)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* :NOTE: This really isn't compatible with big endian but we will never have to worry about that. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (params[4] == 4)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3])
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (params[4] == 2)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (cell_t i = 0; i < params[3]; i++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (params[4] == 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (cell_t i = 0; i < params[3]; i++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Handle_t hndl = static_cast<Handle_t>(params[1]);
 | 
				
			||||||
 | 
						HandleError herr;
 | 
				
			||||||
 | 
						HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | 
				
			||||||
 | 
						FILE *pFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
 | 
				
			||||||
 | 
							!= HandleError_None)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *buffer;
 | 
				
			||||||
 | 
						pContext->LocalToString(params[2], &buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t len = strlen(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (params[3])
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
REGISTER_NATIVES(filesystem)
 | 
					REGISTER_NATIVES(filesystem)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	{"OpenDirectory",			sm_OpenDirectory},
 | 
						{"OpenDirectory",			sm_OpenDirectory},
 | 
				
			||||||
@ -664,5 +855,9 @@ REGISTER_NATIVES(filesystem)
 | 
				
			|||||||
	{"GetFileTime",				sm_GetFileTime},
 | 
						{"GetFileTime",				sm_GetFileTime},
 | 
				
			||||||
	{"LogToOpenFile",			sm_LogToOpenFile},
 | 
						{"LogToOpenFile",			sm_LogToOpenFile},
 | 
				
			||||||
	{"LogToOpenFileEx",			sm_LogToOpenFileEx},
 | 
						{"LogToOpenFileEx",			sm_LogToOpenFileEx},
 | 
				
			||||||
 | 
						{"ReadFile",				sm_ReadFile},
 | 
				
			||||||
 | 
						{"ReadFileString",			sm_ReadFileString},
 | 
				
			||||||
 | 
						{"WriteFile",				sm_WriteFile},
 | 
				
			||||||
 | 
						{"WriteFileString",			sm_WriteFileString},
 | 
				
			||||||
	{NULL,						NULL},
 | 
						{NULL,						NULL},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -158,6 +158,112 @@ native bool:DeleteFile(const String:path[]);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength);
 | 
					native bool:ReadFileLine(Handle:hndl, String:buffer[], maxlength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads binary data from a file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to the file.
 | 
				
			||||||
 | 
					 * @param items			Array to store each item read.  
 | 
				
			||||||
 | 
					 * @param num_items		Number of items to read into the array.
 | 
				
			||||||
 | 
					 * @param size			Size of each element, in bytes, to be read.
 | 
				
			||||||
 | 
					 *						Valid sizes are 1, 2, or 4.
 | 
				
			||||||
 | 
					 * @return				Number of elements read, or -1 on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					native ReadFile(Handle:hndl, items[], num_items, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads a UTF8 or ANSI string from a file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to the file.
 | 
				
			||||||
 | 
					 * @param buffer		Buffer to store the string.
 | 
				
			||||||
 | 
					 * @param max_size		Maximum size of the string buffer.
 | 
				
			||||||
 | 
					 * @param stop			If true, reading will stop once max_size-1 bytes have 
 | 
				
			||||||
 | 
					 *						been read.  If false, reading will stop once a NUL 
 | 
				
			||||||
 | 
					 *						terminator is reached.  The buffer will simply be 
 | 
				
			||||||
 | 
					 *						terminated in either case, the difference is in how 
 | 
				
			||||||
 | 
					 *						the far the file position is changed.
 | 
				
			||||||
 | 
					 * @return				Number of characters written to the buffer, or -1 
 | 
				
			||||||
 | 
					 *						if an error was encountered.
 | 
				
			||||||
 | 
					 * @error				Invalid Handle, or read_count > max_size.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					native ReadFileString(Handle:hndl, String:buffer[], max_size, read_count=-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes binary data to a file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to the file.
 | 
				
			||||||
 | 
					 * @param items			Array of items to write.  The data is read directly. 
 | 
				
			||||||
 | 
					 *						That is, in 1 or 2-byte mode, the lower byte(s) in 
 | 
				
			||||||
 | 
					 *						each cell are used directly, rather than performing 
 | 
				
			||||||
 | 
					 *						any casts from a 4-byte number to a smaller number.
 | 
				
			||||||
 | 
					 * @param num_items		Number of items in the array.
 | 
				
			||||||
 | 
					 * @param size			Size of each item in the array in bytes.  
 | 
				
			||||||
 | 
					 *						Valid sizes are 1, 2, or 4.
 | 
				
			||||||
 | 
					 * @return				True on success, false on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					native bool:WriteFile(Handle:hndl, const items[], num_items, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes a binary string to a file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to th efile.
 | 
				
			||||||
 | 
					 * @param buffer		String to write.
 | 
				
			||||||
 | 
					 * @param term			True to append NUL terminator, false otherwise.
 | 
				
			||||||
 | 
					 * @return				True on success, false on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					native bool:WriteFileString(Handle:hndl, const String:buffer[], bool:term);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes a line of text to a text file.  A newline is automatically appended.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to the file.
 | 
				
			||||||
 | 
					 * @param format		Formatting rules.
 | 
				
			||||||
 | 
					 * @param ...			Variable number of format parameters.
 | 
				
			||||||
 | 
					 * @return				True on success, false otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					native bool:WriteFileLine(Handle:hndl, const String:format[], any:...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads a single binary cell from a file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to the file.
 | 
				
			||||||
 | 
					 * @param data			Variable to store the data read.
 | 
				
			||||||
 | 
					 * @param size			Size of the data to read in bytes.  Valid 
 | 
				
			||||||
 | 
					 *						sizes are 1, 2, or 4 bytes.
 | 
				
			||||||
 | 
					 * @return				Number of elements read (max 1), or -1 on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					stock ReadFileCell(Handle:hndl, &data, size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						new array[1], ret;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ((ret = ReadFile(hndl, array, 1, size)) == 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							data = array[0];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes a single binary cell to a file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param hndl			Handle to the file.
 | 
				
			||||||
 | 
					 * @param data			Cell to write to the file.
 | 
				
			||||||
 | 
					 * @param size			Size of the data to read in bytes.  Valid 
 | 
				
			||||||
 | 
					 *						sizes are 1, 2, or 4 bytes.  If the size 
 | 
				
			||||||
 | 
					 *						is less than 4 bytes, the data is truncated 
 | 
				
			||||||
 | 
					 *						rather than casted.  That is, only the lower 
 | 
				
			||||||
 | 
					 *						bits will be read.
 | 
				
			||||||
 | 
					 * @return				True on success, false on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					stock bool:WriteFileCell(Handle:hndl, data, size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						new array[1];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						array[0] = data;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return WriteFile(hndl, array, 1, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Tests if the end of file has been reached.
 | 
					 * Tests if the end of file has been reached.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@ -171,10 +277,10 @@ native bool:IsEndOfFile(Handle:file);
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param file			Handle to the file.
 | 
					 * @param file			Handle to the file.
 | 
				
			||||||
 * @param position		Position relative to what is specified in whence.
 | 
					 * @param position		Position relative to what is specified in whence.
 | 
				
			||||||
 * @param whence		Look at the SEEK_* definitions.
 | 
					 * @param where			SEEK_ constant value of where to see from.
 | 
				
			||||||
 * @return				True on success, false otherwise.
 | 
					 * @return				True on success, false otherwise.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
native bool:FileSeek(Handle:file, position, whence);
 | 
					native bool:FileSeek(Handle:file, position, where);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Get current position in the file.
 | 
					 * Get current position in the file.
 | 
				
			||||||
@ -235,17 +341,6 @@ native FlushFile(Handle:file);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
native bool:RemoveDir(const String:path[]);
 | 
					native bool:RemoveDir(const String:path[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Writes a line of text in a file.
 | 
					 | 
				
			||||||
 * @note This native will append the newline character.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param hndl			Handle to the file.
 | 
					 | 
				
			||||||
 * @param format		Formatting rules.
 | 
					 | 
				
			||||||
 * @param ...			Variable number of format parameters.
 | 
					 | 
				
			||||||
 * @return				True on success, false otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
native bool:WriteFileLine(Handle:hndl, const String:format[], any:...);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns a file timestamp as a unix timestamp.
 | 
					 * Returns a file timestamp as a unix timestamp.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user