1package eu.siacs.conversations.xmpp.jingle;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.List;
6
7import android.util.Log;
8
9import eu.siacs.conversations.entities.Account;
10import eu.siacs.conversations.entities.Message;
11import eu.siacs.conversations.services.XmppConnectionService;
12import eu.siacs.conversations.xml.Element;
13import eu.siacs.conversations.xmpp.OnIqPacketReceived;
14import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
15import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
16import eu.siacs.conversations.xmpp.stanzas.IqPacket;
17
18public class JingleConnection {
19
20 private JingleConnectionManager mJingleConnectionManager;
21 private XmppConnectionService mXmppConnectionService;
22
23 public static final int STATUS_INITIATED = 0;
24 public static final int STATUS_ACCEPTED = 1;
25 public static final int STATUS_TERMINATED = 2;
26 public static final int STATUS_FAILED = 99;
27
28 private int status = -1;
29 private Message message;
30 private String sessionId;
31 private Account account;
32 private String initiator;
33 private String responder;
34 private List<Element> candidates = new ArrayList<Element>();
35 private HashMap<String, SocksConnection> connections = new HashMap<String, SocksConnection>();
36
37 private OnIqPacketReceived responseListener = new OnIqPacketReceived() {
38
39 @Override
40 public void onIqPacketReceived(Account account, IqPacket packet) {
41 if (packet.getType() == IqPacket.TYPE_ERROR) {
42 mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED);
43 status = STATUS_FAILED;
44 }
45 }
46 };
47
48 public JingleConnection(JingleConnectionManager mJingleConnectionManager) {
49 this.mJingleConnectionManager = mJingleConnectionManager;
50 this.mXmppConnectionService = mJingleConnectionManager.getXmppConnectionService();
51 this.sessionId = this.mJingleConnectionManager.nextRandomId();
52 }
53
54 public String getSessionId() {
55 return this.sessionId;
56 }
57
58 public String getAccountJid() {
59 return this.account.getJid();
60 }
61
62 public String getCounterPart() {
63 return this.message.getCounterpart();
64 }
65
66 public void deliverPacket(JinglePacket packet) {
67
68 if (packet.isAction("session-terminate")) {
69 if (status == STATUS_INITIATED) {
70 mXmppConnectionService.markMessage(message, Message.STATUS_SEND_REJECTED);
71 }
72 status = STATUS_TERMINATED;
73 } else if (packet.isAction("session-accept")) {
74 accept(packet);
75 } else {
76 Log.d("xmppService","packet arrived in connection. action was "+packet.getAction());
77 }
78 }
79
80 public void init(Message message) {
81 this.message = message;
82 this.account = message.getConversation().getAccount();
83 this.initiator = this.account.getFullJid();
84 this.responder = this.message.getCounterpart();
85 if (this.candidates.size() > 0) {
86 this.sendInitRequest();
87 } else {
88 this.mJingleConnectionManager.getPrimaryCandidate(account, new OnPrimaryCandidateFound() {
89
90 @Override
91 public void onPrimaryCandidateFound(boolean success, Element canditate) {
92 if (success) {
93 candidates.add(canditate);
94 }
95 sendInitRequest();
96 }
97 });
98 }
99
100 }
101
102 private void sendInitRequest() {
103 JinglePacket packet = this.bootstrapPacket();
104 packet.setAction("session-initiate");
105 packet.setInitiator(this.account.getFullJid());
106 Content content = new Content();
107 if (message.getType() == Message.TYPE_IMAGE) {
108 content.setAttribute("creator", "initiator");
109 content.setAttribute("name", "a-file-offer");
110 content.offerFile(this.mXmppConnectionService.getFileBackend().getImageFile(message));
111 content.setCandidates(this.mJingleConnectionManager.nextRandomId(),this.candidates);
112 packet.setContent(content);
113 Log.d("xmppService",packet.toString());
114 account.getXmppConnection().sendIqPacket(packet, this.responseListener);
115 this.status = STATUS_INITIATED;
116 }
117 }
118
119 private JinglePacket bootstrapPacket() {
120 JinglePacket packet = new JinglePacket();
121 packet.setFrom(account.getFullJid());
122 packet.setTo(this.message.getCounterpart()); //fixme, not right in all cases;
123 packet.setSessionId(this.sessionId);
124 return packet;
125 }
126
127 private void accept(JinglePacket packet) {
128 Log.d("xmppService","session-accept: "+packet.toString());
129 Content content = packet.getJingleContent();
130 this.candidates.addAll(content.getCanditates());
131 this.status = STATUS_ACCEPTED;
132 this.connectWithCandidates();
133 IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
134 Log.d("xmppService","response "+response.toString());
135 account.getXmppConnection().sendIqPacket(response, null);
136 }
137
138 private void connectWithCandidates() {
139 for(Element canditate : this.candidates) {
140 String host = canditate.getAttribute("host");
141 int port = Integer.parseInt(canditate.getAttribute("port"));
142 SocksConnection socksConnection = new SocksConnection(this, host, port);
143 socksConnection.connect();
144 this.connections.put(canditate.getAttribute("cid"), socksConnection);
145 }
146 }
147
148 private void sendCandidateUsed(String cid) {
149
150 }
151
152 public String getInitiator() {
153 return this.initiator;
154 }
155
156 public String getResponder() {
157 return this.responder;
158 }
159}