JinglePacket.java

  1package eu.siacs.conversations.xmpp.jingle.stanzas;
  2
  3import androidx.annotation.NonNull;
  4
  5import com.google.common.base.CaseFormat;
  6import com.google.common.base.Preconditions;
  7import com.google.common.base.Strings;
  8import com.google.common.collect.ImmutableMap;
  9
 10import eu.siacs.conversations.xml.Element;
 11import eu.siacs.conversations.xml.Namespace;
 12import eu.siacs.conversations.xmpp.Jid;
 13import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 14
 15import java.util.Map;
 16
 17public class JinglePacket extends IqPacket {
 18
 19    private JinglePacket() {
 20        super();
 21    }
 22
 23    public JinglePacket(final Action action, final String sessionId) {
 24        super(TYPE.SET);
 25        final Element jingle = addChild("jingle", Namespace.JINGLE);
 26        jingle.setAttribute("sid", sessionId);
 27        jingle.setAttribute("action", action.toString());
 28    }
 29
 30    public static JinglePacket upgrade(final IqPacket iqPacket) {
 31        Preconditions.checkArgument(iqPacket.hasChild("jingle", Namespace.JINGLE));
 32        Preconditions.checkArgument(iqPacket.getType() == TYPE.SET);
 33        final JinglePacket jinglePacket = new JinglePacket();
 34        jinglePacket.setAttributes(iqPacket.getAttributes());
 35        jinglePacket.setChildren(iqPacket.getChildren());
 36        return jinglePacket;
 37    }
 38
 39    // TODO deprecate this somehow and make file transfer fail if there are multiple (or something)
 40    public Content getJingleContent() {
 41        final Element content = getJingleChild("content");
 42        return content == null ? null : Content.upgrade(content);
 43    }
 44
 45    public Group getGroup() {
 46        final Element jingle = findChild("jingle", Namespace.JINGLE);
 47        final Element group = jingle.findChild("group", Namespace.JINGLE_APPS_GROUPING);
 48        return group == null ? null : Group.upgrade(group);
 49    }
 50
 51    public void addGroup(final Group group) {
 52        this.addJingleChild(group);
 53    }
 54
 55    public Map<String, Content> getJingleContents() {
 56        final Element jingle = findChild("jingle", Namespace.JINGLE);
 57        ImmutableMap.Builder<String, Content> builder = new ImmutableMap.Builder<>();
 58        for (final Element child : jingle.getChildren()) {
 59            if ("content".equals(child.getName())) {
 60                final Content content = Content.upgrade(child);
 61                builder.put(content.getContentName(), content);
 62            }
 63        }
 64        return builder.build();
 65    }
 66
 67    public void addJingleContent(final Content content) { // take content interface
 68        addJingleChild(content);
 69    }
 70
 71    public ReasonWrapper getReason() {
 72        final Element reasonElement = getJingleChild("reason");
 73        if (reasonElement == null) {
 74            return new ReasonWrapper(Reason.UNKNOWN, null);
 75        }
 76        String text = null;
 77        Reason reason = Reason.UNKNOWN;
 78        for (Element child : reasonElement.getChildren()) {
 79            if ("text".equals(child.getName())) {
 80                text = child.getContent();
 81            } else {
 82                reason = Reason.of(child.getName());
 83            }
 84        }
 85        return new ReasonWrapper(reason, text);
 86    }
 87
 88    public void setReason(final Reason reason, final String text) {
 89        final Element jingle = findChild("jingle", Namespace.JINGLE);
 90        final Element reasonElement = jingle.addChild("reason");
 91        reasonElement.addChild(reason.toString());
 92        if (!Strings.isNullOrEmpty(text)) {
 93            reasonElement.addChild("text").setContent(text);
 94        }
 95    }
 96
 97    // RECOMMENDED for session-initiate, NOT RECOMMENDED otherwise
 98    public void setInitiator(final Jid initiator) {
 99        Preconditions.checkArgument(initiator.isFullJid(), "initiator should be a full JID");
100        findChild("jingle", Namespace.JINGLE).setAttribute("initiator", initiator);
101    }
102
103    // RECOMMENDED for session-accept, NOT RECOMMENDED otherwise
104    public void setResponder(Jid responder) {
105        Preconditions.checkArgument(responder.isFullJid(), "responder should be a full JID");
106        findChild("jingle", Namespace.JINGLE).setAttribute("responder", responder);
107    }
108
109    public Element getJingleChild(final String name) {
110        final Element jingle = findChild("jingle", Namespace.JINGLE);
111        return jingle == null ? null : jingle.findChild(name);
112    }
113
114    public void addJingleChild(final Element child) {
115        final Element jingle = findChild("jingle", Namespace.JINGLE);
116        jingle.addChild(child);
117    }
118
119    public String getSessionId() {
120        return findChild("jingle", Namespace.JINGLE).getAttribute("sid");
121    }
122
123    public Action getAction() {
124        return Action.of(findChild("jingle", Namespace.JINGLE).getAttribute("action"));
125    }
126
127    public enum Action {
128        CONTENT_ACCEPT,
129        CONTENT_ADD,
130        CONTENT_MODIFY,
131        CONTENT_REJECT,
132        CONTENT_REMOVE,
133        DESCRIPTION_INFO,
134        SECURITY_INFO,
135        SESSION_ACCEPT,
136        SESSION_INFO,
137        SESSION_INITIATE,
138        SESSION_TERMINATE,
139        TRANSPORT_ACCEPT,
140        TRANSPORT_INFO,
141        TRANSPORT_REJECT,
142        TRANSPORT_REPLACE;
143
144        public static Action of(final String value) {
145            // TODO handle invalid
146            return Action.valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, value));
147        }
148
149        @Override
150        @NonNull
151        public String toString() {
152            return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, super.toString());
153        }
154    }
155
156    public static class ReasonWrapper {
157        public final Reason reason;
158        public final String text;
159
160        public ReasonWrapper(Reason reason, String text) {
161            this.reason = reason;
162            this.text = text;
163        }
164    }
165}