JingleInbandTransport.java

  1package eu.siacs.conversations.xmpp.jingle;
  2
  3import java.io.FileInputStream;
  4import java.io.FileNotFoundException;
  5import java.io.FileOutputStream;
  6import java.io.IOException;
  7import java.security.MessageDigest;
  8import java.security.NoSuchAlgorithmException;
  9
 10import android.util.Base64;
 11import android.util.Log;
 12import eu.siacs.conversations.entities.Account;
 13import eu.siacs.conversations.utils.CryptoHelper;
 14import eu.siacs.conversations.xml.Element;
 15import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 16import eu.siacs.conversations.xmpp.PacketReceived;
 17import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 18
 19public class JingleInbandTransport extends JingleTransport {
 20
 21	private Account account;
 22	private String counterpart;
 23	private int blockSize;
 24	private int bufferSize;
 25	private int seq = 0;
 26	private String sessionId;
 27
 28	private boolean established = false;
 29
 30	private JingleFile file;
 31	
 32	private FileInputStream fileInputStream = null;
 33	private FileOutputStream fileOutputStream;
 34	private long remainingSize;
 35	private MessageDigest digest;
 36
 37	private OnFileTransmitted onFileTransmitted;
 38	
 39	private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() {
 40		@Override
 41		public void onIqPacketReceived(Account account, IqPacket packet) {
 42			Log.d("xmppService", "on ack received");
 43			if (packet.getType() == IqPacket.TYPE_RESULT) {
 44				sendNextBlock();
 45			}
 46		}
 47	};
 48
 49	public JingleInbandTransport(Account account, String counterpart,
 50			String sid, int blocksize) {
 51		this.account = account;
 52		this.counterpart = counterpart;
 53		this.blockSize = blocksize;
 54		this.bufferSize = blocksize / 4;
 55		this.sessionId = sid;
 56	}
 57
 58	public void connect(final OnTransportConnected callback) {
 59		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
 60		iq.setTo(this.counterpart);
 61		Element open = iq.addChild("open", "http://jabber.org/protocol/ibb");
 62		open.setAttribute("sid", this.sessionId);
 63		open.setAttribute("stanza", "iq");
 64		open.setAttribute("block-size", "" + this.blockSize);
 65
 66		this.account.getXmppConnection().sendIqPacket(iq,
 67				new OnIqPacketReceived() {
 68
 69					@Override
 70					public void onIqPacketReceived(Account account,
 71							IqPacket packet) {
 72						if (packet.getType() == IqPacket.TYPE_ERROR) {
 73							callback.failed();
 74						} else {
 75							callback.established();
 76						}
 77					}
 78				});
 79	}
 80
 81	@Override
 82	public void receive(JingleFile file, OnFileTransmitted callback) {
 83		this.onFileTransmitted = callback;
 84		this.file = file;
 85		Log.d("xmppService", "receiving file over ibb");
 86		try {
 87			this.digest = MessageDigest.getInstance("SHA-1");
 88			digest.reset();
 89			file.getParentFile().mkdirs();
 90			file.createNewFile();
 91			this.fileOutputStream = new FileOutputStream(file);
 92			this.remainingSize = file.getExpectedSize();
 93		} catch (NoSuchAlgorithmException e) {
 94			e.printStackTrace();
 95		} catch (IOException e) {
 96			e.printStackTrace();
 97		}
 98	}
 99
100	@Override
101	public void send(JingleFile file, OnFileTransmitted callback) {
102		this.onFileTransmitted = callback;
103		this.file = file;
104		Log.d("xmppService", "sending file over ibb");
105		try {
106			this.digest = MessageDigest.getInstance("SHA-1");
107			this.digest.reset();
108			fileInputStream = new FileInputStream(file);
109			this.sendNextBlock();
110		} catch (FileNotFoundException e) {
111			e.printStackTrace();
112		} catch (NoSuchAlgorithmException e) {
113			e.printStackTrace();
114		}
115	}
116
117	private void sendNextBlock() {
118		byte[] buffer = new byte[this.bufferSize];
119		try {
120			int count = fileInputStream.read(buffer);
121			if (count==-1) {
122				file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
123				fileInputStream.close();
124				this.onFileTransmitted.onFileTransmitted(file);
125			} else {
126				this.digest.update(buffer);
127				String base64 = Base64.encodeToString(buffer, Base64.DEFAULT);
128				IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
129				iq.setTo(this.counterpart);
130				Element data = iq
131						.addChild("data", "http://jabber.org/protocol/ibb");
132				data.setAttribute("seq", "" + this.seq);
133				data.setAttribute("block-size", "" + this.blockSize);
134				data.setAttribute("sid", this.sessionId);
135				data.setContent(base64);
136				this.account.getXmppConnection().sendIqPacket(iq,
137						this.onAckReceived);
138				this.seq++;
139			}
140		} catch (IOException e) {
141			// TODO Auto-generated catch block
142			e.printStackTrace();
143		}
144	}
145
146	private void receiveNextBlock(String data) {
147		try {
148			byte[] buffer = Base64.decode(data, Base64.DEFAULT);
149			this.remainingSize -= buffer.length;
150
151			this.fileOutputStream.write(buffer);
152
153			this.digest.update(buffer);
154			Log.d("xmppService", "remaining file size:" + this.remainingSize);
155			if (this.remainingSize <= 0) {
156				file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
157				Log.d("xmppService","file name: "+file.getAbsolutePath());
158				fileOutputStream.flush();
159				fileOutputStream.close();
160				this.onFileTransmitted.onFileTransmitted(file);
161			}
162		} catch (IOException e) {
163			e.printStackTrace();
164		}
165	}
166
167	public void deliverPayload(IqPacket packet, Element payload) {
168		if (payload.getName().equals("open")) {
169			if (!established) {
170				established = true;
171				this.account.getXmppConnection().sendIqPacket(
172						packet.generateRespone(IqPacket.TYPE_RESULT), null);
173			} else {
174				this.account.getXmppConnection().sendIqPacket(
175						packet.generateRespone(IqPacket.TYPE_ERROR), null);
176			}
177		} else if (payload.getName().equals("data")) {
178			this.receiveNextBlock(payload.getContent());
179			this.account.getXmppConnection().sendIqPacket(
180					packet.generateRespone(IqPacket.TYPE_RESULT), null);
181		} else {
182			Log.d("xmppServic","couldnt deliver payload "+packet.toString());
183		}
184	}
185}