mirror of
https://github.com/umjammer/JBinHex.git
synced 2025-01-11 19:29:42 +00:00
fix some resource leaks
This commit is contained in:
parent
7c84ea4385
commit
30a46ddfba
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/bin/
|
||||
/docs/
|
||||
/tmp/
|
103
README.md
Normal file
103
README.md
Normal file
@ -0,0 +1,103 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>JBinHex</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#ff0000" ALINK="#ff00ff" VLINK="#990000">
|
||||
|
||||
<H1 ALIGN="center">JBinHex</H1>
|
||||
|
||||
<P><FONT SIZE=+1>
|
||||
JBinHex is both a library and a command-line tool to decode files in
|
||||
the Apple Macintosh BinHex 4.0 format.
|
||||
</FONT></P>
|
||||
|
||||
<H2>Current version: 0.5</H2>
|
||||
|
||||
<H3>Version history:</H3>
|
||||
|
||||
<DL>
|
||||
<DT>0.5
|
||||
<DD>First released version
|
||||
</DL>
|
||||
|
||||
<H3>Limitations in this version:</H3>
|
||||
|
||||
<MENU>
|
||||
<LI>This version does not support segmented files such as used
|
||||
on comp.binaries.mac.* newsgroups
|
||||
<LI>Documentation is limited
|
||||
<LI>Command line tool has does not check wether the command line
|
||||
parameters are completely correct
|
||||
</MENU>
|
||||
|
||||
<H3>Possible future features:</H3>
|
||||
|
||||
<UL>
|
||||
<LI>Encoding of BinHex files
|
||||
<LI>File-based interface that allows to switch between data and
|
||||
resource fork at any moment, instead of the predetermined order
|
||||
that the stream-based interface dictates
|
||||
</UL>
|
||||
|
||||
<H3>Command-line tool</H3>
|
||||
|
||||
<P>The class name of the command-line tool is <CODE>org.gjt.convert.binhex.DeBinHex</CODE></P>
|
||||
|
||||
<P>It accepts the following command line parameters:</P>
|
||||
|
||||
<MENU>
|
||||
<LI>Either <CODE>-u <url></CODE> or <CODE>-f <file></CODE>
|
||||
to specify the source BinHexed file. If neither of those options
|
||||
is present, <CODE>DeBinHex</CODE> reads <CODE>stdin</CODE>.
|
||||
<LI><CODE>-d</CODE> to decode the data fork. It will be put in
|
||||
the file with the name that came from the BinHex header.
|
||||
<LI><CODE>-df <filename></CODE> to decode the data fork
|
||||
to the named file instead of the name that came from the BinHex
|
||||
header.
|
||||
<LI><CODE>-r</CODE> to decode the resource fork. It will be put
|
||||
in the file with the name that came from the BinHex header, with
|
||||
the extension "<CODE>.resource</CODE>" appended to
|
||||
it.
|
||||
<LI><CODE>-rf <filename></CODE> to decode the resource
|
||||
fork to the named file instead of the name that came from the
|
||||
BinHex header.
|
||||
<LI>Both <CODE>-d</CODE>/<CODE>-df</CODE> options and <CODE>-r</CODE>/<CODE>-rf</CODE>
|
||||
may be present at the same time. If none of these options is
|
||||
present, <CODE>DeBinHex</CODE> will decode the data fork as if
|
||||
the <CODE>-d</CODE> options was specified.
|
||||
<LI><CODE>-h</CODE> to only show the header of the BinHex file
|
||||
on <CODE>stdout</CODE>. The decoding options are ignored.
|
||||
</MENU>
|
||||
|
||||
<H3>Javadoc</H3>
|
||||
The <A HREF="javadoc/index.html">Javadoc of the classes</A> is included in the
|
||||
distribution and available online.
|
||||
|
||||
<H3>Download</H3>
|
||||
|
||||
<P><A HREF="http://www.klomp.org/packages/JBinHex.tar.gz">Download the complete package</A> including source, javadoc and jarfile with classes (36 Kb).</P>
|
||||
|
||||
<H3>License</H3>
|
||||
|
||||
<P>The package is licensed under the <B>GNU General Public License</B>,
|
||||
also known as the GPL license. See file <A HREF="COPYING">COPYING</A> for
|
||||
details.</P>
|
||||
|
||||
<H3>References</H3>
|
||||
|
||||
<UL>
|
||||
<LI>Article written by Yves Lempereur, available as Appendix A in <A HREF="http://www.rfc.net/get2.php3/rfc1741.html">rfc1741</A>
|
||||
<LI>Article titled <A HREF="http://wuarchive.wustl.edu/systems/mac/umich.edu/misc/documentation/binhex4.0specs.txt">"BinHex 4.0 Definition"</A> by Peter N Lewis
|
||||
</UL>
|
||||
|
||||
<H3>Copyright</H3>
|
||||
|
||||
<P>All files in the package and on this site Copyright 2000 by Erwin
|
||||
Bolwidt, <<A HREF="mailto:ejb@klomp.org">ejb@klomp.org</A>></P>
|
||||
|
||||
<HR ALIGN=LEFT>
|
||||
<FONT SIZE="-1">This page was last updated at april 8, 2000.</FONT>
|
||||
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
35
pom.xml
Normal file
35
pom.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>klomp.org</groupId>
|
||||
<artifactId>jbinhex</artifactId>
|
||||
<version>0.0.6</version>
|
||||
|
||||
<url>http://www.klomp.org/JBinHex/JBinHex.html</url>
|
||||
<name>JBinHex</name>
|
||||
<description>both a library and a command-line tool to decode files in the Apple Macintosh BinHex 4.0 format.
|
||||
|
||||
0.0.6
|
||||
|
||||
mavenize
|
||||
fix some resource leaks</description>
|
||||
<scm>
|
||||
<url>https://github.com/umjammer/JBinHex</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
<url>https://github.com/umjammer/JBinHex/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -19,8 +19,9 @@
|
||||
|
||||
package org.gjt.convert.binhex;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
This class completely decodes a BinHex4 file in three parts: the header,
|
||||
@ -54,14 +55,14 @@ public class BinHex4InputStream extends InputStream {
|
||||
{
|
||||
/**
|
||||
The name that this file had before encoding in BinHex4. The bytes
|
||||
represent characters in the Macintosh character set.
|
||||
represent characters in the Macintosh character set.
|
||||
*/
|
||||
byte[] fileName;
|
||||
|
||||
/**
|
||||
The version of this file. Usually 0. This is a special feature of
|
||||
the Macintosh file system that is, to my knowledge, infrequently
|
||||
used.
|
||||
used.
|
||||
*/
|
||||
int version;
|
||||
|
||||
@ -218,7 +219,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
|
||||
/**
|
||||
Constructs a BinHex4InputStream from a stream that is a source of 7-bit
|
||||
Hqx7 encoded data. This is the typical use for files fetched from the
|
||||
Hqx7 encoded data. This is the typical use for files fetched from the
|
||||
Internet or through e-mail.
|
||||
*/
|
||||
public BinHex4InputStream(InputStream source)
|
||||
@ -228,7 +229,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
|
||||
/**
|
||||
Constructs a BinHex4InputStream from a stream that is either a source
|
||||
of 7-bit Hqx7 encoded data or of pure 8-bit data in Hqx8 format. The
|
||||
of 7-bit Hqx7 encoded data or of pure 8-bit data in Hqx8 format. The
|
||||
flag eightBit tells this class what to expect.
|
||||
|
||||
@param source
|
||||
@ -262,7 +263,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
checkDataCRC();
|
||||
switchState(stateInDataFork);
|
||||
} catch(IOException e)
|
||||
{
|
||||
{
|
||||
switchState(stateError);
|
||||
throw e;
|
||||
}
|
||||
@ -272,7 +273,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
{
|
||||
if((header == null && newState != stateError) || streamState == stateError)
|
||||
throw new IllegalStateException(
|
||||
"Cannot switch state with header == null or in errorState");
|
||||
"Cannot switch state with header == null or in errorState");
|
||||
|
||||
if(newState == stateInDataFork)
|
||||
{
|
||||
@ -281,7 +282,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
hardEndOfFork = false;
|
||||
seenEndOfFork = false;
|
||||
}
|
||||
else if(newState == stateInResourceFork)
|
||||
else if(newState == stateInResourceFork)
|
||||
{
|
||||
bytesLeftInFork = header.resourceLength;
|
||||
hqxIn.resetCRC();
|
||||
@ -304,16 +305,16 @@ public class BinHex4InputStream extends InputStream {
|
||||
readHeader();
|
||||
else if(streamState == stateInResourceFork)
|
||||
throw new IOException(
|
||||
"Sorry, no random access. Cannot switch back from "
|
||||
+ "resource to data fork.");
|
||||
"Sorry, no random access. Cannot switch back from "
|
||||
+ "resource to data fork.");
|
||||
else if(streamState != stateInDataFork)
|
||||
throw new IllegalStateException("Stream is in unknown state.");
|
||||
}
|
||||
|
||||
/**
|
||||
Swtich to reading from the resource fork. All methods derived from
|
||||
InputStream will apply to the resource fork. This method cannot be
|
||||
called after any method has thrown an IOException.
|
||||
InputStream will apply to the resource fork. This method cannot be
|
||||
called after any method has thrown an IOException.
|
||||
*/
|
||||
public void useResourceFork() throws IOException
|
||||
{
|
||||
@ -419,7 +420,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
throw new IOException("Incorrect CRC (calculated:"+calculatedCRC+" != file:"+readCRC+")");
|
||||
}
|
||||
|
||||
private void skipToEndOfFork() throws IOException
|
||||
private void skipToEndOfFork() throws IOException
|
||||
{
|
||||
skip(bytesLeftInFork);
|
||||
}
|
||||
@ -450,8 +451,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try {
|
||||
BinHex4InputStream in = new BinHex4InputStream(System.in);
|
||||
try (BinHex4InputStream in = new BinHex4InputStream(System.in)) {
|
||||
System.err.println(in.getHeader());
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
@ -465,7 +465,7 @@ public class BinHex4InputStream extends InputStream {
|
||||
System.out.write(buf, 0, r);
|
||||
}
|
||||
} catch(IOException e)
|
||||
{
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,12 @@
|
||||
|
||||
package org.gjt.convert.binhex;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
Command line program to decode binhex files from the harddisk or from
|
||||
@ -73,7 +76,7 @@ public class DeBinHex
|
||||
if(inFile != null)
|
||||
binhexIn = new FileInputStream(inFile);
|
||||
else
|
||||
{
|
||||
{
|
||||
String urlString = findValueOption("-u", args);
|
||||
if(urlString != null)
|
||||
{
|
||||
@ -116,8 +119,8 @@ public class DeBinHex
|
||||
return args[i+1];
|
||||
else
|
||||
throw new RuntimeException(
|
||||
"Cannot use option that needs an argument "
|
||||
+ "as the last option");
|
||||
"Cannot use option that needs an argument "
|
||||
+ "as the last option");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -134,9 +137,9 @@ public class DeBinHex
|
||||
}
|
||||
|
||||
public static void action(
|
||||
InputStream binhexIn, boolean justHeader,
|
||||
boolean doData, String dataOut,
|
||||
boolean doResource, String resourceOut) throws IOException
|
||||
InputStream binhexIn, boolean justHeader,
|
||||
boolean doData, String dataOut,
|
||||
boolean doResource, String resourceOut) throws IOException
|
||||
{
|
||||
BinHex4InputStream binhex;
|
||||
|
||||
@ -144,6 +147,7 @@ public class DeBinHex
|
||||
if(justHeader)
|
||||
{
|
||||
System.out.println(binhex.getHeader());
|
||||
binhex.close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,10 @@
|
||||
|
||||
package org.gjt.convert.binhex;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.io.EOFException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
Converts a 7-bit encoded binhex4.0 data stream to a 8-bit encoded
|
||||
@ -39,7 +41,7 @@ import java.io.*;
|
||||
public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
|
||||
final static String validChars
|
||||
= "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`"
|
||||
= "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`"
|
||||
+ "abcdefhijklmpqr";
|
||||
|
||||
final static String binhexHeaderId = "(This file must be converted with BinHex";
|
||||
@ -68,8 +70,8 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
// string. This whole class wouldn't work if they had.
|
||||
if(validChars.length() != 64)
|
||||
throw new IllegalStateException(
|
||||
"Incorrect class, the static validChars entry should "
|
||||
+ "be 64 characters long.");
|
||||
"Incorrect class, the static validChars entry should "
|
||||
+ "be 64 characters long.");
|
||||
for(int i = 0; i < sixBitTable.length; i++)
|
||||
{
|
||||
// 64 is the 'invalid character' value
|
||||
@ -166,7 +168,7 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
// Debug line
|
||||
// System.err.print((char)streamBuffer[sbIndex]);
|
||||
// Take care to return no sign-extended numbers, hence the & 0xff
|
||||
return ((int)streamBuffer[sbIndex++]) & 0xff;
|
||||
return (streamBuffer[sbIndex++]) & 0xff;
|
||||
}
|
||||
|
||||
sbFilled = super.read(streamBuffer, 0, streamBuffer.length);
|
||||
@ -182,7 +184,7 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
// Debug line
|
||||
// System.err.print((char)streamBuffer[sbIndex]);
|
||||
// Take care to return no sign-extended numbers, hence the & 0xff
|
||||
return ((int)streamBuffer[sbIndex++]) & 0xff;
|
||||
return (streamBuffer[sbIndex++]) & 0xff;
|
||||
}
|
||||
|
||||
private int next6bits() throws IOException
|
||||
@ -190,7 +192,7 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
if(hardEOF)
|
||||
throw new EOFException(
|
||||
"All Hqx7 data was read and a soft EOF was already "
|
||||
+ "reported with a -1 return to read().");
|
||||
+ "reported with a -1 return to read().");
|
||||
|
||||
int b;
|
||||
do {
|
||||
@ -199,14 +201,14 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
// with a : character.
|
||||
if(b == -1)
|
||||
throw new EOFException(
|
||||
"EOF reached before closing : character. "
|
||||
+ "Possible data corruption.");
|
||||
"EOF reached before closing : character. "
|
||||
+ "Possible data corruption.");
|
||||
|
||||
// The high bit could have been used as a parity bit. Better be sure.
|
||||
b &= 0x7f;
|
||||
|
||||
// The : character terminates the stream
|
||||
if(b == ':') {
|
||||
if(b == ':') {
|
||||
hardEOF = true;
|
||||
return -1;
|
||||
}
|
||||
@ -216,8 +218,8 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
int v = sixBitTable[b];
|
||||
if(v == invalidEntry)
|
||||
throw new IOException(
|
||||
"Illegal character in Hqx7 stream encountered, "
|
||||
+ "possible data corruption. ('" + (char)b + "')");
|
||||
"Illegal character in Hqx7 stream encountered, "
|
||||
+ "possible data corruption. ('" + (char)b + "')");
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -299,8 +301,7 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try {
|
||||
InputStream in = new Hqx7_to_Hqx8InputStream(System.in);
|
||||
try (InputStream in = new Hqx7_to_Hqx8InputStream(System.in)) {
|
||||
byte[] buf = new byte[1024];
|
||||
|
||||
System.err.println("Starting to convert");
|
||||
@ -312,7 +313,7 @@ public class Hqx7_to_Hqx8InputStream extends FilterInputStream {
|
||||
System.out.write(buf, 0, r);
|
||||
}
|
||||
} catch(IOException e)
|
||||
{
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,10 @@
|
||||
|
||||
package org.gjt.convert.binhex;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.io.EOFException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
Decodes Run-length encoding LE from a 8-bit BinHex stream and calculates
|
||||
@ -45,7 +47,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
|
||||
/**
|
||||
Constructs a RLE_CRCInputStream from a stream that is a source of 7-bit
|
||||
Hqx7 encoded data. This is the typical use for files fetched from the
|
||||
Hqx7 encoded data. This is the typical use for files fetched from the
|
||||
Internet or through e-mail. Internally, a Hqx7_to_Hqx8InputStream is
|
||||
created to translate from 7-bit to 8-bit format before passing the data
|
||||
through this stream.
|
||||
@ -57,7 +59,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
|
||||
/**
|
||||
Constructs a RLE_CRCInputStream from a stream that is either a source
|
||||
of 7-bit Hqx7 encoded data or of pure 8-bit data in Hqx8 format. The
|
||||
of 7-bit Hqx7 encoded data or of pure 8-bit data in Hqx8 format. The
|
||||
flag eightBit tells this class what to expect.
|
||||
|
||||
@param source
|
||||
@ -88,7 +90,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
|
||||
if(sbIndex < sbFilled)
|
||||
// Take care to return no sign-extended numbers, hence the & 0xff
|
||||
return ((int)streamBuffer[sbIndex++]) & 0xff;
|
||||
return (streamBuffer[sbIndex++]) & 0xff;
|
||||
|
||||
sbFilled = super.read(streamBuffer, 0, streamBuffer.length);
|
||||
if(sbFilled <= 0)
|
||||
@ -99,10 +101,10 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
|
||||
sbIndex = 0;
|
||||
// Take care to return no sign-extended numbers, hence the & 0xff
|
||||
return ((int)streamBuffer[sbIndex++]) & 0xff;
|
||||
return (streamBuffer[sbIndex++]) & 0xff;
|
||||
}
|
||||
|
||||
private int nextDecodedByte() throws IOException
|
||||
private int nextDecodedByte() throws IOException
|
||||
{
|
||||
// Check if we're still busy expanding a run-length-encoding.
|
||||
// No reads are necessary in that case.
|
||||
@ -134,8 +136,8 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
int c = nextStreamByte();
|
||||
if(c == -1)
|
||||
throw new EOFException(
|
||||
"Corrupted Hqx8 stream, EOF just after a "
|
||||
+ "0x90 RLE char.");
|
||||
"Corrupted Hqx8 stream, EOF just after a "
|
||||
+ "0x90 RLE char.");
|
||||
if(c == 0)
|
||||
{
|
||||
// No RLE, just a single 0x90 character
|
||||
@ -155,7 +157,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
updateCRC(lastByte);
|
||||
return lastByte;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// Plain old straight data passing through. Do remember this
|
||||
// as the lastByte though, because the next character could
|
||||
@ -196,7 +198,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
Returns the CRC calculated over the data that was read since the beginning
|
||||
of the stream or since the last call to resetCRC.
|
||||
Must only be called after all the data was read in a section, because
|
||||
the CRC is updated as if two extra 0 bytes were read. This is dictated
|
||||
the CRC is updated as if two extra 0 bytes were read. This is dictated
|
||||
by the BinHex4 protocol.
|
||||
*/
|
||||
public int getCRC()
|
||||
@ -255,8 +257,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try {
|
||||
InputStream in = new RLE_CRCInputStream(System.in);
|
||||
try (InputStream in = new RLE_CRCInputStream(System.in)) {
|
||||
byte[] buf = new byte[1024];
|
||||
|
||||
System.err.println("Starting to convert");
|
||||
@ -268,7 +269,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
System.out.write(buf, 0, r);
|
||||
}
|
||||
} catch(IOException e)
|
||||
{
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ -287,7 +288,7 @@ public class RLE_CRCInputStream extends FilterInputStream {
|
||||
|
||||
/**
|
||||
If inRLE is true, then nextDecodedByte will return the byte
|
||||
<code>lastByte</code> another <code>rleRepeat</code> times.
|
||||
<code>lastByte</code> another <code>rleRepeat</code> times.
|
||||
*/
|
||||
private int rleRepeat;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user