CarrotChat v2.8.60.240131版本的 MD5 值为:2baf8b9f31830b86b5c5a85ae6b47e05
以下内容为反编译后的 InBandBytestreamSession.java 源代码,内容仅作参考
package org.jivesoftware.smackx.bytestreams.ibb;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketTimeoutException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jxmpp.jid.Jid;
public class InBandBytestreamSession implements BytestreamSession {
private final Open byteStreamRequest;
private final XMPPConnection connection;
private IBBInputStream inputStream;
private IBBOutputStream outputStream;
private Jid remoteJID;
private boolean closeBothStreamsEnabled = false;
private boolean isClosed = false;
static class AnonymousClass1 {
static final int[] $SwitchMap$org$jivesoftware$smackx$bytestreams$ibb$InBandBytestreamManager$StanzaType;
static {
int[] iArr = new int[InBandBytestreamManager.StanzaType.values().length];
$SwitchMap$org$jivesoftware$smackx$bytestreams$ibb$InBandBytestreamManager$StanzaType = iArr;
try {
iArr[InBandBytestreamManager.StanzaType.IQ.ordinal()] = 1;
} catch (NoSuchFieldError unused) {
}
try {
$SwitchMap$org$jivesoftware$smackx$bytestreams$ibb$InBandBytestreamManager$StanzaType[InBandBytestreamManager.StanzaType.MESSAGE.ordinal()] = 2;
} catch (NoSuchFieldError unused2) {
}
}
}
private class IBBDataPacketFilter implements StanzaFilter {
private IBBDataPacketFilter() {
}
@Override
public boolean accept(Stanza stanza) {
DataPacketExtension dataPacketExtension;
if (stanza.getFrom().equals((CharSequence) InBandBytestreamSession.this.remoteJID)) {
if (stanza instanceof Data) {
dataPacketExtension = ((Data) stanza).getDataPacketExtension();
} else {
dataPacketExtension = (DataPacketExtension) stanza.getExtension("data", "http://jabber.org/protocol/ibb");
if (dataPacketExtension == null) {
return false;
}
}
return dataPacketExtension.getSessionID().equals(InBandBytestreamSession.this.byteStreamRequest.getSessionID());
}
return false;
}
IBBDataPacketFilter(InBandBytestreamSession inBandBytestreamSession, AnonymousClass1 anonymousClass1) {
this();
}
}
private class IQIBBInputStream extends IBBInputStream {
private IQIBBInputStream() {
super();
}
@Override
protected StanzaFilter getDataPacketFilter() {
return new AndFilter(new StanzaTypeFilter(Data.class), new IBBDataPacketFilter(InBandBytestreamSession.this, null));
}
@Override
protected StanzaListener getDataPacketListener() {
return new StanzaListener() {
private long lastSequence = -1;
@Override
public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException {
DataPacketExtension dataPacketExtension = ((Data) stanza).getDataPacketExtension();
if (dataPacketExtension.getSeq() <= this.lastSequence) {
InBandBytestreamSession.this.connection.sendStanza(IQ.createErrorResponse((IQ) stanza, XMPPError.Condition.unexpected_request));
} else if (dataPacketExtension.getDecodedData() == null) {
InBandBytestreamSession.this.connection.sendStanza(IQ.createErrorResponse((IQ) stanza, XMPPError.Condition.bad_request));
} else {
IQIBBInputStream.this.dataQueue.offer(dataPacketExtension);
InBandBytestreamSession.this.connection.sendStanza(IQ.createResultIQ((IQ) stanza));
long seq = dataPacketExtension.getSeq();
this.lastSequence = seq;
if (seq == 65535) {
this.lastSequence = -1L;
}
}
}
};
}
IQIBBInputStream(InBandBytestreamSession inBandBytestreamSession, AnonymousClass1 anonymousClass1) {
this();
}
}
private class IQIBBOutputStream extends IBBOutputStream {
private IQIBBOutputStream() {
super();
}
@Override
protected synchronized void writeToXML(DataPacketExtension dataPacketExtension) throws IOException {
Data data = new Data(dataPacketExtension);
data.setTo(InBandBytestreamSession.this.remoteJID);
try {
InBandBytestreamSession.this.connection.createStanzaCollectorAndSend(data).nextResultOrThrow();
} catch (Exception e2) {
if (!this.isClosed) {
InBandBytestreamSession.this.close();
IOException iOException = new IOException();
iOException.initCause(e2);
throw iOException;
}
}
}
IQIBBOutputStream(InBandBytestreamSession inBandBytestreamSession, AnonymousClass1 anonymousClass1) {
this();
}
}
private class MessageIBBInputStream extends IBBInputStream {
private MessageIBBInputStream() {
super();
}
@Override
protected StanzaFilter getDataPacketFilter() {
return new AndFilter(new StanzaTypeFilter(Message.class), new IBBDataPacketFilter(InBandBytestreamSession.this, null));
}
@Override
protected StanzaListener getDataPacketListener() {
return new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
DataPacketExtension dataPacketExtension = (DataPacketExtension) stanza.getExtension("data", "http://jabber.org/protocol/ibb");
if (dataPacketExtension.getDecodedData() == null) {
return;
}
MessageIBBInputStream.this.dataQueue.offer(dataPacketExtension);
}
};
}
MessageIBBInputStream(InBandBytestreamSession inBandBytestreamSession, AnonymousClass1 anonymousClass1) {
this();
}
}
private class MessageIBBOutputStream extends IBBOutputStream {
private MessageIBBOutputStream() {
super();
}
@Override
protected synchronized void writeToXML(DataPacketExtension dataPacketExtension) throws SmackException.NotConnectedException, InterruptedException {
Message message = new Message(InBandBytestreamSession.this.remoteJID);
message.addExtension(dataPacketExtension);
InBandBytestreamSession.this.connection.sendStanza(message);
}
MessageIBBOutputStream(InBandBytestreamSession inBandBytestreamSession, AnonymousClass1 anonymousClass1) {
this();
}
}
public InBandBytestreamSession(XMPPConnection xMPPConnection, Open open, Jid jid) {
this.connection = xMPPConnection;
this.byteStreamRequest = open;
this.remoteJID = jid;
int i = AnonymousClass1.$SwitchMap$org$jivesoftware$smackx$bytestreams$ibb$InBandBytestreamManager$StanzaType[open.getStanza().ordinal()];
if (i == 1) {
this.inputStream = new IQIBBInputStream(this, null);
this.outputStream = new IQIBBOutputStream(this, null);
} else if (i != 2) {
} else {
this.inputStream = new MessageIBBInputStream(this, null);
this.outputStream = new MessageIBBOutputStream(this, null);
}
}
@Override
public void close() throws IOException {
closeByLocal(true);
closeByLocal(false);
}
protected synchronized void closeByLocal(boolean z) throws IOException {
if (this.isClosed) {
return;
}
if (this.closeBothStreamsEnabled) {
this.inputStream.closeInternal();
this.outputStream.closeInternal(true);
} else if (z) {
this.inputStream.closeInternal();
} else {
this.outputStream.closeInternal(true);
}
if (this.inputStream.isClosed && this.outputStream.isClosed) {
this.isClosed = true;
Close close = new Close(this.byteStreamRequest.getSessionID());
close.setTo(this.remoteJID);
try {
this.connection.createStanzaCollectorAndSend(close).nextResultOrThrow();
this.inputStream.cleanup();
InBandBytestreamManager.getByteStreamManager(this.connection).getSessions().remove(this.byteStreamRequest.getSessionID());
} catch (Exception e2) {
IOException iOException = new IOException();
iOException.initCause(e2);
throw iOException;
}
}
}
public void closeByPeer(Close close) throws SmackException.NotConnectedException, InterruptedException {
this.inputStream.closeInternal();
this.inputStream.cleanup();
this.outputStream.closeInternal(false);
this.connection.sendStanza(IQ.createResultIQ(close));
}
@Override
public InputStream getInputStream() {
return this.inputStream;
}
@Override
public OutputStream getOutputStream() {
return this.outputStream;
}
@Override
public int getReadTimeout() {
return this.inputStream.readTimeout;
}
public boolean isCloseBothStreamsEnabled() {
return this.closeBothStreamsEnabled;
}
public void processIQPacket(Data data) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
this.inputStream.dataPacketListener.processStanza(data);
}
public void setCloseBothStreamsEnabled(boolean z) {
this.closeBothStreamsEnabled = z;
}
@Override
public void setReadTimeout(int i) {
if (i >= 0) {
this.inputStream.readTimeout = i;
return;
}
throw new IllegalArgumentException("Timeout must be >= 0");
}
public abstract class IBBInputStream extends InputStream {
private byte[] buffer;
private final StanzaListener dataPacketListener;
protected final BlockingQueue<DataPacketExtension> dataQueue = new LinkedBlockingQueue();
private int bufferPointer = -1;
private long seq = -1;
private boolean isClosed = false;
private boolean closeInvoked = false;
private int readTimeout = 0;
public IBBInputStream() {
StanzaListener dataPacketListener = getDataPacketListener();
this.dataPacketListener = dataPacketListener;
InBandBytestreamSession.this.connection.addSyncStanzaListener(dataPacketListener, getDataPacketFilter());
}
private void checkClosed() throws IOException {
if (this.closeInvoked) {
this.dataQueue.clear();
throw new IOException("Stream is closed");
}
}
public void cleanup() {
InBandBytestreamSession.this.connection.removeSyncStanzaListener(this.dataPacketListener);
}
public void closeInternal() {
if (this.isClosed) {
return;
}
this.isClosed = true;
}
private synchronized boolean loadBuffer() throws IOException {
DataPacketExtension poll;
try {
int i = this.readTimeout;
if (i == 0) {
poll = null;
while (poll == null) {
if (this.isClosed && this.dataQueue.isEmpty()) {
return false;
}
poll = this.dataQueue.poll(1000L, TimeUnit.MILLISECONDS);
}
} else {
poll = this.dataQueue.poll(i, TimeUnit.MILLISECONDS);
if (poll == null) {
throw new SocketTimeoutException();
}
}
if (this.seq == 65535) {
this.seq = -1L;
}
long seq = poll.getSeq();
if (seq - 1 == this.seq) {
this.seq = seq;
this.buffer = poll.getDecodedData();
this.bufferPointer = 0;
return true;
}
InBandBytestreamSession.this.close();
throw new IOException("Packets out of sequence");
} catch (InterruptedException unused) {
Thread.currentThread().interrupt();
return false;
}
}
@Override
public void close() throws IOException {
if (this.closeInvoked) {
return;
}
this.closeInvoked = true;
InBandBytestreamSession.this.closeByLocal(true);
}
protected abstract StanzaFilter getDataPacketFilter();
protected abstract StanzaListener getDataPacketListener();
@Override
public boolean markSupported() {
return false;
}
@Override
public synchronized int read() throws IOException {
checkClosed();
int i = this.bufferPointer;
if ((i == -1 || i >= this.buffer.length) && !loadBuffer()) {
return -1;
}
byte[] bArr = this.buffer;
int i2 = this.bufferPointer;
this.bufferPointer = i2 + 1;
return bArr[i2] & 255;
}
@Override
public synchronized int read(byte[] bArr, int i, int i2) throws IOException {
int i3;
if (bArr != null) {
if (i < 0 || i > bArr.length || i2 < 0 || (i3 = i + i2) > bArr.length || i3 < 0) {
throw new IndexOutOfBoundsException();
}
if (i2 == 0) {
return 0;
}
checkClosed();
int i4 = this.bufferPointer;
if ((i4 == -1 || i4 >= this.buffer.length) && !loadBuffer()) {
return -1;
}
byte[] bArr2 = this.buffer;
int length = bArr2.length;
int i5 = this.bufferPointer;
int i6 = length - i5;
if (i2 > i6) {
i2 = i6;
}
System.arraycopy(bArr2, i5, bArr, i, i2);
this.bufferPointer += i2;
return i2;
}
throw new NullPointerException();
}
@Override
public synchronized int read(byte[] bArr) throws IOException {
return read(bArr, 0, bArr.length);
}
}
public abstract class IBBOutputStream extends OutputStream {
protected final byte[] buffer;
protected int bufferPointer = 0;
protected long seq = 0;
protected boolean isClosed = false;
public IBBOutputStream() {
this.buffer = new byte[InBandBytestreamSession.this.byteStreamRequest.getBlockSize()];
}
private synchronized void flushBuffer() throws IOException {
int i = this.bufferPointer;
if (i == 0) {
return;
}
try {
writeToXML(new DataPacketExtension(InBandBytestreamSession.this.byteStreamRequest.getSessionID(), this.seq, Base64.encodeToString(this.buffer, 0, i)));
this.bufferPointer = 0;
long j = this.seq;
this.seq = j + 1 == 65535 ? 0L : j + 1;
} catch (InterruptedException | SmackException.NotConnectedException e2) {
IOException iOException = new IOException();
iOException.initCause(e2);
throw iOException;
}
}
private synchronized void writeOut(byte[] bArr, int i, int i2) throws IOException {
if (!this.isClosed) {
int i3 = 0;
byte[] bArr2 = this.buffer;
int length = bArr2.length;
int i4 = this.bufferPointer;
if (i2 > length - i4) {
i3 = bArr2.length - i4;
System.arraycopy(bArr, i, bArr2, i4, i3);
this.bufferPointer += i3;
flushBuffer();
}
int i5 = i2 - i3;
System.arraycopy(bArr, i + i3, this.buffer, this.bufferPointer, i5);
this.bufferPointer += i5;
} else {
throw new IOException("Stream is closed");
}
}
@Override
public void close() throws IOException {
if (this.isClosed) {
return;
}
InBandBytestreamSession.this.closeByLocal(false);
}
protected void closeInternal(boolean z) {
if (this.isClosed) {
return;
}
this.isClosed = true;
if (z) {
try {
flushBuffer();
} catch (IOException unused) {
}
}
}
@Override
public synchronized void flush() throws IOException {
if (!this.isClosed) {
flushBuffer();
} else {
throw new IOException("Stream is closed");
}
}
@Override
public synchronized void write(int i) throws IOException {
if (!this.isClosed) {
if (this.bufferPointer >= this.buffer.length) {
flushBuffer();
}
byte[] bArr = this.buffer;
int i2 = this.bufferPointer;
this.bufferPointer = i2 + 1;
bArr[i2] = (byte) i;
} else {
throw new IOException("Stream is closed");
}
}
protected abstract void writeToXML(DataPacketExtension dataPacketExtension) throws IOException, SmackException.NotConnectedException, InterruptedException;
@Override
public synchronized void write(byte[] bArr, int i, int i2) throws IOException {
int i3;
if (bArr != null) {
if (i < 0 || i > bArr.length || i2 < 0 || (i3 = i + i2) > bArr.length || i3 < 0) {
throw new IndexOutOfBoundsException();
}
if (i2 == 0) {
return;
}
if (!this.isClosed) {
byte[] bArr2 = this.buffer;
if (i2 >= bArr2.length) {
writeOut(bArr, i, bArr2.length);
byte[] bArr3 = this.buffer;
write(bArr, i + bArr3.length, i2 - bArr3.length);
} else {
writeOut(bArr, i, i2);
}
return;
}
throw new IOException("Stream is closed");
}
throw new NullPointerException();
}
@Override
public synchronized void write(byte[] bArr) throws IOException {
write(bArr, 0, bArr.length);
}
}
}