1package eu.siacs.conversations.xmpp.jingle.stanzas;
2
3import android.util.Log;
4
5import com.google.common.base.Preconditions;
6import com.google.common.base.Strings;
7import com.google.common.collect.ImmutableList;
8
9import eu.siacs.conversations.Config;
10import eu.siacs.conversations.xml.Element;
11import eu.siacs.conversations.xml.Namespace;
12import eu.siacs.conversations.xmpp.jingle.transports.SocksByteStreamsTransport;
13
14import java.util.Collection;
15import java.util.List;
16
17public class SocksByteStreamsTransportInfo extends GenericTransportInfo {
18
19 private SocksByteStreamsTransportInfo() {
20 super("transport", Namespace.JINGLE_TRANSPORTS_S5B);
21 }
22
23 public String getTransportId() {
24 return this.getAttribute("sid");
25 }
26
27 public SocksByteStreamsTransportInfo(
28 final String transportId,
29 final Collection<SocksByteStreamsTransport.Candidate> candidates) {
30 super("transport", Namespace.JINGLE_TRANSPORTS_S5B);
31 Preconditions.checkNotNull(transportId, "transport id must not be null");
32 for (SocksByteStreamsTransport.Candidate candidate : candidates) {
33 this.addChild(candidate.asElement());
34 }
35 this.setAttribute("sid", transportId);
36 }
37
38 public TransportInfo getTransportInfo() {
39 if (hasChild("proxy-error")) {
40 return new ProxyError();
41 } else if (hasChild("candidate-error")) {
42 return new CandidateError();
43 } else if (hasChild("candidate-used")) {
44 final Element candidateUsed = findChild("candidate-used");
45 final String cid = candidateUsed == null ? null : candidateUsed.getAttribute("cid");
46 if (Strings.isNullOrEmpty(cid)) {
47 return null;
48 } else {
49 return new CandidateUsed(cid);
50 }
51 } else if (hasChild("activated")) {
52 final Element activated = findChild("activated");
53 final String cid = activated == null ? null : activated.getAttribute("cid");
54 if (Strings.isNullOrEmpty(cid)) {
55 return null;
56 } else {
57 return new Activated(cid);
58 }
59 } else {
60 return null;
61 }
62 }
63
64 public List<SocksByteStreamsTransport.Candidate> getCandidates() {
65 final ImmutableList.Builder<SocksByteStreamsTransport.Candidate> candidateBuilder =
66 new ImmutableList.Builder<>();
67 for (final Element child : getChildren()) {
68 if ("candidate".equals(child.getName())
69 && Namespace.JINGLE_TRANSPORTS_S5B.equals(child.getNamespace())) {
70 try {
71 candidateBuilder.add(SocksByteStreamsTransport.Candidate.of(child));
72 } catch (final Exception e) {
73 Log.d(Config.LOGTAG, "skip over broken candidate", e);
74 }
75 }
76 }
77 return candidateBuilder.build();
78 }
79
80 public static SocksByteStreamsTransportInfo upgrade(final Element element) {
81 Preconditions.checkArgument(
82 "transport".equals(element.getName()), "Name of provided element is not transport");
83 Preconditions.checkArgument(
84 Namespace.JINGLE_TRANSPORTS_S5B.equals(element.getNamespace()),
85 "Element does not match s5b transport namespace");
86 final SocksByteStreamsTransportInfo transportInfo = new SocksByteStreamsTransportInfo();
87 transportInfo.setAttributes(element.getAttributes());
88 transportInfo.setChildren(element.getChildren());
89 return transportInfo;
90 }
91
92 public String getDestinationAddress() {
93 return this.getAttribute("dstaddr");
94 }
95
96 public abstract static class TransportInfo {}
97
98 public static class CandidateUsed extends TransportInfo {
99 public final String cid;
100
101 public CandidateUsed(String cid) {
102 this.cid = cid;
103 }
104 }
105
106 public static class Activated extends TransportInfo {
107 public final String cid;
108
109 public Activated(final String cid) {
110 this.cid = cid;
111 }
112 }
113
114 public static class CandidateError extends TransportInfo {}
115
116 public static class ProxyError extends TransportInfo {}
117}