1package eu.siacs.conversations.xmpp.jingle;
2
3import java.math.BigInteger;
4import java.security.SecureRandom;
5import java.util.HashMap;
6import java.util.List;
7import java.util.concurrent.CopyOnWriteArrayList;
8import android.annotation.SuppressLint;
9import android.util.Log;
10import eu.siacs.conversations.Config;
11import eu.siacs.conversations.entities.Account;
12import eu.siacs.conversations.entities.Message;
13import eu.siacs.conversations.services.XmppConnectionService;
14import eu.siacs.conversations.xml.Element;
15import eu.siacs.conversations.xmpp.OnIqPacketReceived;
16import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
17import eu.siacs.conversations.xmpp.stanzas.IqPacket;
18
19public class JingleConnectionManager {
20
21 private XmppConnectionService xmppConnectionService;
22
23 private List<JingleConnection> connections = new CopyOnWriteArrayList<JingleConnection>();
24
25 private HashMap<String, JingleCandidate> primaryCandidates = new HashMap<String, JingleCandidate>();
26
27 @SuppressLint("TrulyRandom")
28 private SecureRandom random = new SecureRandom();
29
30 public JingleConnectionManager(XmppConnectionService service) {
31 this.xmppConnectionService = service;
32 }
33
34 public void deliverPacket(Account account, JinglePacket packet) {
35 if (packet.isAction("session-initiate")) {
36 JingleConnection connection = new JingleConnection(this);
37 connection.init(account, packet);
38 connections.add(connection);
39 } else {
40 for (JingleConnection connection : connections) {
41 if (connection.getAccountJid().equals(account.getFullJid())
42 && connection.getSessionId().equals(
43 packet.getSessionId())
44 && connection.getCounterPart().equals(packet.getFrom())) {
45 connection.deliverPacket(packet);
46 return;
47 }
48 }
49 account.getXmppConnection().sendIqPacket(
50 packet.generateRespone(IqPacket.TYPE_ERROR), null);
51 }
52 }
53
54 public JingleConnection createNewConnection(Message message) {
55 JingleConnection connection = new JingleConnection(this);
56 connection.init(message);
57 this.connections.add(connection);
58 return connection;
59 }
60
61 public JingleConnection createNewConnection(JinglePacket packet) {
62 JingleConnection connection = new JingleConnection(this);
63 this.connections.add(connection);
64 return connection;
65 }
66
67 public void finishConnection(JingleConnection connection) {
68 this.connections.remove(connection);
69 }
70
71 public XmppConnectionService getXmppConnectionService() {
72 return this.xmppConnectionService;
73 }
74
75 public void getPrimaryCandidate(Account account,
76 final OnPrimaryCandidateFound listener) {
77 if (!this.primaryCandidates.containsKey(account.getJid())) {
78 String xmlns = "http://jabber.org/protocol/bytestreams";
79 final String proxy = account.getXmppConnection()
80 .findDiscoItemByFeature(xmlns);
81 if (proxy != null) {
82 IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
83 iq.setTo(proxy);
84 iq.query(xmlns);
85 account.getXmppConnection().sendIqPacket(iq,
86 new OnIqPacketReceived() {
87
88 @Override
89 public void onIqPacketReceived(Account account,
90 IqPacket packet) {
91 Element streamhost = packet
92 .query()
93 .findChild("streamhost",
94 "http://jabber.org/protocol/bytestreams");
95 if (streamhost != null) {
96 JingleCandidate candidate = new JingleCandidate(
97 nextRandomId(), true);
98 candidate.setHost(streamhost
99 .getAttribute("host"));
100 candidate.setPort(Integer
101 .parseInt(streamhost
102 .getAttribute("port")));
103 candidate
104 .setType(JingleCandidate.TYPE_PROXY);
105 candidate.setJid(proxy);
106 candidate.setPriority(655360 + 65535);
107 primaryCandidates.put(account.getJid(),
108 candidate);
109 listener.onPrimaryCandidateFound(true,
110 candidate);
111 } else {
112 listener.onPrimaryCandidateFound(false,
113 null);
114 }
115 }
116 });
117 } else {
118 listener.onPrimaryCandidateFound(false, null);
119 }
120
121 } else {
122 listener.onPrimaryCandidateFound(true,
123 this.primaryCandidates.get(account.getJid()));
124 }
125 }
126
127 public String nextRandomId() {
128 return new BigInteger(50, random).toString(32);
129 }
130
131 public long getAutoAcceptFileSize() {
132 String config = this.xmppConnectionService.getPreferences().getString(
133 "auto_accept_file_size", "524288");
134 try {
135 return Long.parseLong(config);
136 } catch (NumberFormatException e) {
137 return 524288;
138 }
139 }
140
141 public void deliverIbbPacket(Account account, IqPacket packet) {
142 String sid = null;
143 Element payload = null;
144 if (packet.hasChild("open", "http://jabber.org/protocol/ibb")) {
145 payload = packet
146 .findChild("open", "http://jabber.org/protocol/ibb");
147 sid = payload.getAttribute("sid");
148 } else if (packet.hasChild("data", "http://jabber.org/protocol/ibb")) {
149 payload = packet
150 .findChild("data", "http://jabber.org/protocol/ibb");
151 sid = payload.getAttribute("sid");
152 }
153 if (sid != null) {
154 for (JingleConnection connection : connections) {
155 if (connection.hasTransportId(sid)) {
156 JingleTransport transport = connection.getTransport();
157 if (transport instanceof JingleInbandTransport) {
158 JingleInbandTransport inbandTransport = (JingleInbandTransport) transport;
159 inbandTransport.deliverPayload(packet, payload);
160 return;
161 }
162 }
163 }
164 Log.d(Config.LOGTAG,
165 "couldnt deliver payload: " + payload.toString());
166 } else {
167 Log.d(Config.LOGTAG, "no sid found in incomming ibb packet");
168 }
169 }
170
171 public void cancelInTransmission() {
172 for (JingleConnection connection : this.connections) {
173 if (connection.getStatus() == JingleConnection.STATUS_TRANSMITTING) {
174 connection.cancel();
175 }
176 }
177 }
178}