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