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 java.util.Locale;
 12import java.util.Set;
 13
 14import eu.siacs.conversations.Config;
 15import eu.siacs.conversations.xml.Element;
 16import eu.siacs.conversations.xml.Namespace;
 17import eu.siacs.conversations.xmpp.jingle.SessionDescription;
 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 (FileTransferDescription.NAMESPACES.contains(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 S5BTransportInfo.upgrade(transport);
 94        } else if (Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(namespace)) {
 95            return IceUdpTransportInfo.upgrade(transport);
 96        } else if (transport != null) {
 97            return GenericTransportInfo.upgrade(transport);
 98        } else {
 99            return null;
100        }
101    }
102
103
104    public void setTransport(GenericTransportInfo transportInfo) {
105        this.addChild(transportInfo);
106    }
107
108    public enum Creator {
109        INITIATOR,
110        RESPONDER;
111
112        public static Creator of(final String value) {
113            return Creator.valueOf(value.toUpperCase(Locale.ROOT));
114        }
115
116        @Override
117        @NonNull
118        public String toString() {
119            return super.toString().toLowerCase(Locale.ROOT);
120        }
121    }
122
123    public enum Senders {
124        BOTH,
125        INITIATOR,
126        NONE,
127        RESPONDER;
128
129        public static Senders of(final String value) {
130            return Senders.valueOf(value.toUpperCase(Locale.ROOT));
131        }
132
133        public static Senders of(final SessionDescription.Media media, final boolean initiator) {
134            final Set<String> attributes = media.attributes.keySet();
135            if (attributes.contains("sendrecv")) {
136                return BOTH;
137            } else if (attributes.contains("inactive")) {
138                return NONE;
139            } else if (attributes.contains("sendonly")) {
140                return initiator ? INITIATOR : RESPONDER;
141            } else if (attributes.contains("recvonly")) {
142                return initiator ? RESPONDER : INITIATOR;
143            }
144            Log.w(Config.LOGTAG,"assuming default value for senders");
145            // If none of the attributes "sendonly", "recvonly", "inactive", and "sendrecv" is
146            // present, "sendrecv" SHOULD be assumed as the default
147            // https://www.rfc-editor.org/rfc/rfc4566
148            return BOTH;
149        }
150
151        public static Set<Senders> receiveOnly(final boolean initiator) {
152            return ImmutableSet.of(initiator ? RESPONDER : INITIATOR);
153        }
154
155        @Override
156        @NonNull
157        public String toString() {
158            return super.toString().toLowerCase(Locale.ROOT);
159        }
160
161        public String asMediaAttribute(final boolean initiator) {
162            final boolean responder = !initiator;
163            if (this == Content.Senders.BOTH) {
164                return "sendrecv";
165            } else if (this == Content.Senders.NONE) {
166                return "inactive";
167            } else if ((initiator && this == Content.Senders.INITIATOR)
168                    || (responder && this == Content.Senders.RESPONDER)) {
169                return "sendonly";
170            } else if ((initiator && this == Content.Senders.RESPONDER)
171                    || (responder && this == Content.Senders.INITIATOR)) {
172                return "recvonly";
173            } else {
174                throw new IllegalStateException(
175                        String.format(
176                                "illegal combination of initiator=%s and %s", initiator, this));
177            }
178        }
179    }
180}