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