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