Content.java

  1package eu.siacs.conversations.xmpp.jingle.stanzas;
  2
  3import android.util.Log;
  4
  5import androidx.annotation.NonNull;
  6
  7import com.google.common.base.Preconditions;
  8import com.google.common.base.Strings;
  9import com.google.common.collect.ImmutableSet;
 10
 11import eu.siacs.conversations.Config;
 12import eu.siacs.conversations.xml.Element;
 13import eu.siacs.conversations.xml.Namespace;
 14import eu.siacs.conversations.xmpp.jingle.SessionDescription;
 15
 16import java.util.Locale;
 17import java.util.Set;
 18
 19public class Content extends Element {
 20
 21    public Content(final Creator creator, final Senders senders, final String name) {
 22        super("content", Namespace.JINGLE);
 23        this.setAttribute("creator", creator.toString());
 24        this.setAttribute("name", name);
 25        this.setSenders(senders);
 26    }
 27
 28    private Content() {
 29        super("content", Namespace.JINGLE);
 30    }
 31
 32    public static Content upgrade(final Element element) {
 33        Preconditions.checkArgument("content".equals(element.getName()));
 34        final Content content = new Content();
 35        content.setAttributes(element.getAttributes());
 36        content.setChildren(element.getChildren());
 37        return content;
 38    }
 39
 40    public String getContentName() {
 41        return this.getAttribute("name");
 42    }
 43
 44    public Creator getCreator() {
 45        return Creator.of(getAttribute("creator"));
 46    }
 47
 48    public Senders getSenders() {
 49        final String attribute = getAttribute("senders");
 50        if (Strings.isNullOrEmpty(attribute)) {
 51            return Senders.BOTH;
 52        }
 53        return Senders.of(getAttribute("senders"));
 54    }
 55
 56    public void setSenders(final Senders senders) {
 57        if (senders != null && senders != Senders.BOTH) {
 58            this.setAttribute("senders", senders.toString());
 59        }
 60    }
 61
 62    public GenericDescription getDescription() {
 63        final Element description = this.findChild("description");
 64        if (description == null) {
 65            return null;
 66        }
 67        final String namespace = description.getNamespace();
 68        if (Namespace.JINGLE_APPS_FILE_TRANSFER.equals(namespace)) {
 69            return FileTransferDescription.upgrade(description);
 70        } else if (Namespace.JINGLE_APPS_RTP.equals(namespace)) {
 71            return RtpDescription.upgrade(description);
 72        } else {
 73            return GenericDescription.upgrade(description);
 74        }
 75    }
 76
 77    public void setDescription(final GenericDescription description) {
 78        Preconditions.checkNotNull(description);
 79        this.addChild(description);
 80    }
 81
 82    public String getDescriptionNamespace() {
 83        final Element description = this.findChild("description");
 84        return description == null ? null : description.getNamespace();
 85    }
 86
 87    public GenericTransportInfo getTransport() {
 88        final Element transport = this.findChild("transport");
 89        final String namespace = transport == null ? null : transport.getNamespace();
 90        if (Namespace.JINGLE_TRANSPORTS_IBB.equals(namespace)) {
 91            return IbbTransportInfo.upgrade(transport);
 92        } else if (Namespace.JINGLE_TRANSPORTS_S5B.equals(namespace)) {
 93            return SocksByteStreamsTransportInfo.upgrade(transport);
 94        } else if (Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(namespace)) {
 95            return IceUdpTransportInfo.upgrade(transport);
 96        } else if (Namespace.JINGLE_TRANSPORT_WEBRTC_DATA_CHANNEL.equals(namespace)) {
 97            return WebRTCDataChannelTransportInfo.upgrade(transport);
 98        } else if (transport != null) {
 99            return GenericTransportInfo.upgrade(transport);
100        } else {
101            return null;
102        }
103    }
104
105    public void setTransport(GenericTransportInfo transportInfo) {
106        this.addChild(transportInfo);
107    }
108
109    public enum Creator {
110        INITIATOR,
111        RESPONDER;
112
113        public static Creator of(final String value) {
114            return Creator.valueOf(value.toUpperCase(Locale.ROOT));
115        }
116
117        @Override
118        @NonNull
119        public String toString() {
120            return super.toString().toLowerCase(Locale.ROOT);
121        }
122    }
123
124    public enum Senders {
125        BOTH,
126        INITIATOR,
127        NONE,
128        RESPONDER;
129
130        public static Senders of(final String value) {
131            return Senders.valueOf(value.toUpperCase(Locale.ROOT));
132        }
133
134        public static Senders of(final SessionDescription.Media media, final boolean initiator) {
135            final Set<String> attributes = media.attributes.keySet();
136            if (attributes.contains("sendrecv")) {
137                return BOTH;
138            } else if (attributes.contains("inactive")) {
139                return NONE;
140            } else if (attributes.contains("sendonly")) {
141                return initiator ? INITIATOR : RESPONDER;
142            } else if (attributes.contains("recvonly")) {
143                return initiator ? RESPONDER : INITIATOR;
144            }
145            Log.w(Config.LOGTAG, "assuming default value for senders");
146            // If none of the attributes "sendonly", "recvonly", "inactive", and "sendrecv" is
147            // present, "sendrecv" SHOULD be assumed as the default
148            // https://www.rfc-editor.org/rfc/rfc4566
149            return BOTH;
150        }
151
152        public static Set<Senders> receiveOnly(final boolean initiator) {
153            return ImmutableSet.of(initiator ? RESPONDER : INITIATOR);
154        }
155
156        @Override
157        @NonNull
158        public String toString() {
159            return super.toString().toLowerCase(Locale.ROOT);
160        }
161
162        public String asMediaAttribute(final boolean initiator) {
163            final boolean responder = !initiator;
164            if (this == Content.Senders.BOTH) {
165                return "sendrecv";
166            } else if (this == Content.Senders.NONE) {
167                return "inactive";
168            } else if ((initiator && this == Content.Senders.INITIATOR)
169                    || (responder && this == Content.Senders.RESPONDER)) {
170                return "sendonly";
171            } else if ((initiator && this == Content.Senders.RESPONDER)
172                    || (responder && this == Content.Senders.INITIATOR)) {
173                return "recvonly";
174            } else {
175                throw new IllegalStateException(
176                        String.format(
177                                "illegal combination of initiator=%s and %s", initiator, this));
178            }
179        }
180    }
181}