/** * * Copyright 2017 Paul Schaub * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.smackx.jingle_filetransfer.component; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.jingle.component.JingleSession; import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionInfoElement; import org.jivesoftware.smackx.jingle.element.JingleElement; import org.jivesoftware.smackx.jingle_filetransfer.controller.IncomingFileOfferController; import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement; /** * Behind the scenes logic of an incoming Jingle file offer. * Created by vanitas on 26.07.17. */ public class JingleIncomingFileOffer extends AbstractJingleFileOffer implements IncomingFileOfferController { private static final Logger LOGGER = Logger.getLogger(JingleIncomingFileOffer.class.getName()); private OutputStream target; public JingleIncomingFileOffer(JingleFileTransferChildElement offer) { super(new JingleFileTransferFile.RemoteFile(offer)); } @Override public JingleElement handleDescriptionInfo(JingleContentDescriptionInfoElement info) { return null; } @Override public void onBytestreamReady(BytestreamSession bytestreamSession) { if (target == null) { throw new IllegalStateException("Target OutputStream is null"); } LOGGER.log(Level.INFO, "Receive file"); InputStream inputStream = null; try { inputStream = bytestreamSession.getInputStream(); int length = 0; int read = 0; byte[] bufbuf = new byte[4096]; while ((length = inputStream.read(bufbuf)) >= 0) { target.write(bufbuf, 0, length); read += length; LOGGER.log(Level.INFO, "Read " + read + " (" + length + ") of " + file.getSize() + " bytes."); if (read == (int) file.getSize()) { break; } } LOGGER.log(Level.INFO, "Reading/Writing finished."); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Cannot get InputStream from BytestreamSession: " + e, e); } finally { if (inputStream != null) { try { inputStream.close(); LOGGER.log(Level.INFO, "CipherInputStream closed."); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Could not close InputStream: " + e, e); } } if (target != null) { try { target.close(); LOGGER.log(Level.INFO, "FileOutputStream closed."); } catch (IOException e) { LOGGER.log(Level.SEVERE, "Could not close OutputStream: " + e, e); } } } notifyProgressListenersFinished(); } @Override public boolean isOffer() { return true; } @Override public boolean isRequest() { return false; } @Override public void accept(XMPPConnection connection, File target) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, IOException { if (!target.exists()) { target.createNewFile(); } this.target = new FileOutputStream(target); JingleSession session = getParent().getParent(); if (session.getSessionState() == JingleSession.SessionState.pending) { session.sendAccept(connection); } } @Override public void accept(XMPPConnection connection, OutputStream stream) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { target = stream; JingleSession session = getParent().getParent(); if (session.getSessionState() == JingleSession.SessionState.pending) { session.sendAccept(connection); } } @Override public JingleFileTransferFile.RemoteFile getFile() { return (JingleFileTransferFile.RemoteFile) this.file; } }