001/**
002 *
003 * Copyright 2017 Paul Schaub
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements;
018
019import org.jivesoftware.smack.packet.XmlEnvironment;
020import org.jivesoftware.smack.util.InternetAddress;
021import org.jivesoftware.smack.util.Objects;
022import org.jivesoftware.smack.util.StringUtils;
023import org.jivesoftware.smack.util.XmlStringBuilder;
024
025import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
026import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate;
027
028import org.jxmpp.jid.Jid;
029import org.jxmpp.jid.impl.JidCreate;
030import org.jxmpp.stringprep.XmppStringprepException;
031
032/**
033 * TransportCandidate for Jingle Socks5Bytestream transports.
034 */
035public final class JingleS5BTransportCandidate extends JingleContentTransportCandidate {
036
037    public static final String NAMESPACE = JingleS5BTransport.NAMESPACE_V1;
038
039    public static final String ATTR_CID = "cid";
040    public static final String ATTR_HOST = "host";
041    public static final String ATTR_JID = "jid";
042    public static final String ATTR_PORT = "port";
043    public static final String ATTR_PRIORITY = "priority";
044    public static final String ATTR_TYPE = "type";
045
046    private final String cid;
047    private final InternetAddress host;
048    private final Jid jid;
049    private final int port;
050    private final int priority;
051    private final Type type;
052
053    public JingleS5BTransportCandidate(String candidateId, String hostString, Jid jid, int port, int priority, Type type) {
054        this(candidateId, InternetAddress.from(hostString), jid, port, priority, type);
055    }
056
057    public JingleS5BTransportCandidate(String candidateId, InternetAddress host, Jid jid, int port, int priority, Type type) {
058        Objects.requireNonNull(candidateId);
059        Objects.requireNonNull(host);
060        Objects.requireNonNull(jid);
061
062        if (priority < 0) {
063            throw new IllegalArgumentException("Priority MUST NOT be less than 0.");
064        }
065        if (port < 0) {
066            throw new IllegalArgumentException("Port MUST NOT be less than 0.");
067        }
068
069        this.cid = candidateId;
070        this.host = host;
071        this.jid = jid;
072        this.port = port;
073        this.priority = priority;
074        this.type = type;
075    }
076
077    public JingleS5BTransportCandidate(Bytestream.StreamHost streamHost, int priority, Type type) {
078        this(StringUtils.randomString(24), streamHost.getAddress(), streamHost.getJID(), streamHost.getPort(), priority, type);
079    }
080
081    public enum Type {
082        assisted (120),
083        direct (126),
084        proxy (10),
085        tunnel (110),
086        ;
087
088        private final int weight;
089
090        public int getWeight() {
091            return weight;
092        }
093
094        Type(int weight) {
095            this.weight = weight;
096        }
097
098        public static Type fromString(String name) {
099            for (Type t : Type.values()) {
100                if (t.toString().equals(name)) {
101                    return t;
102                }
103            }
104            throw new IllegalArgumentException("Illegal type: " + name);
105        }
106    }
107
108    public String getCandidateId() {
109        return cid;
110    }
111
112    public InternetAddress getHost() {
113        return host;
114    }
115
116    public Jid getJid() {
117        return jid;
118    }
119
120    public int getPort() {
121        return port;
122    }
123
124    public int getPriority() {
125        return priority;
126    }
127
128    public Type getType() {
129        return type;
130    }
131
132    public Bytestream.StreamHost getStreamHost() {
133        return new Bytestream.StreamHost(jid, host, port);
134    }
135
136
137    @Override
138    public String getNamespace() {
139        return NAMESPACE;
140    }
141
142    @Override
143    public XmlStringBuilder toXML(XmlEnvironment enclosingXmlEnvironment) {
144        XmlStringBuilder xml = new XmlStringBuilder(this, enclosingXmlEnvironment);
145        xml.attribute(ATTR_CID, cid);
146        xml.attribute(ATTR_HOST, host);
147        xml.attribute(ATTR_JID, jid);
148        if (port >= 0) {
149            xml.attribute(ATTR_PORT, port);
150        }
151        xml.attribute(ATTR_PRIORITY, priority);
152        xml.optAttribute(ATTR_TYPE, type);
153
154        xml.closeEmptyElement();
155        return xml;
156    }
157
158    public static Builder getBuilder() {
159        return new Builder();
160    }
161
162    public static final class Builder {
163        private String cid;
164        private InternetAddress host;
165        private Jid jid;
166        private int port = -1;
167        private int priority = -1;
168        private Type type;
169
170        private Builder() {
171        }
172
173        public Builder setCandidateId(String cid) {
174            this.cid = cid;
175            return this;
176        }
177
178        public Builder setHost(String host)  {
179            InternetAddress inetAddress = InternetAddress.from(host);
180            return setHost(inetAddress);
181        }
182
183        public Builder setHost(InternetAddress host) {
184            this.host = host;
185            return this;
186        }
187
188        public Builder setJid(String jid) throws XmppStringprepException {
189            this.jid = JidCreate.from(jid);
190            return this;
191        }
192
193        public Builder setPort(int port) {
194            if (port < 0) {
195                throw new IllegalArgumentException("Port MUST NOT be less than 0.");
196            }
197            this.port = port;
198            return this;
199        }
200
201        public Builder setPriority(int priority) {
202            if (priority < 0) {
203                throw new IllegalArgumentException("Priority MUST NOT be less than 0.");
204            }
205            this.priority = priority;
206            return this;
207        }
208
209        public Builder setType(Type type) {
210            this.type = type;
211            return this;
212        }
213
214        public JingleS5BTransportCandidate build() {
215            return new JingleS5BTransportCandidate(cid, host, jid, port, priority, type);
216        }
217    }
218
219}