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);
        }
    }
}