1package eu.siacs.conversations.entities;
2
3import android.content.ContentValues;
4import android.util.Base64;
5import java.io.UnsupportedEncodingException;
6import java.lang.Comparable;
7import java.security.MessageDigest;
8import java.security.NoSuchAlgorithmException;
9import java.util.ArrayList;
10import java.util.Collections;
11import java.util.List;
12import org.json.JSONArray;
13import org.json.JSONException;
14import org.json.JSONObject;
15
16import eu.siacs.conversations.xml.Element;
17import eu.siacs.conversations.xmpp.stanzas.IqPacket;
18
19public class ServiceDiscoveryResult {
20
21 protected static String blankNull(String s) {
22 return s == null ? "" : s;
23 }
24
25 public static class Identity implements Comparable {
26 protected final String category;
27 protected final String type;
28 protected final String lang;
29 protected final String name;
30
31 public Identity(final String category, final String type, final String lang, final String name) {
32 this.category = category;
33 this.type = type;
34 this.lang = lang;
35 this.name = name;
36 }
37
38 public Identity(final Element el) {
39 this.category = el.getAttribute("category");
40 this.type = el.getAttribute("type");
41 this.lang = el.getAttribute("xml:lang");
42 this.name = el.getAttribute("name");
43 }
44
45 public String getCategory() {
46 return this.category;
47 }
48
49 public String getType() {
50 return this.type;
51 }
52
53 public String getLang() {
54 return this.lang;
55 }
56
57 public String getName() {
58 return this.name;
59 }
60
61 public int compareTo(Object other) {
62 Identity o = (Identity)other;
63 int r = blankNull(this.getCategory()).compareTo(blankNull(o.getCategory()));
64 if(r == 0) {
65 r = blankNull(this.getType()).compareTo(blankNull(o.getType()));
66 }
67 if(r == 0) {
68 r = blankNull(this.getLang()).compareTo(blankNull(o.getLang()));
69 }
70 if(r == 0) {
71 r = blankNull(this.getName()).compareTo(blankNull(o.getName()));
72 }
73
74 return r;
75 }
76
77 public JSONObject toJSON() {
78 try {
79 JSONObject o = new JSONObject();
80 o.put("category", this.getCategory());
81 o.put("type", this.getType());
82 o.put("lang", this.getLang());
83 o.put("name", this.getName());
84 return o;
85 } catch(JSONException e) {
86 return null;
87 }
88 }
89 }
90
91 protected final List<Identity> identities;
92 protected final List<String> features;
93
94 public ServiceDiscoveryResult(final List<Identity> identities, final List<String> features) {
95 this.identities = identities;
96 this.features = features;
97 }
98
99 public ServiceDiscoveryResult(final IqPacket packet) {
100 this.identities = new ArrayList<>();
101 this.features = new ArrayList<>();
102
103 final List<Element> elements = packet.query().getChildren();
104
105 for (final Element element : elements) {
106 if (element.getName().equals("identity")) {
107 Identity id = new Identity(element);
108 if (id.getType() != null && id.getCategory() != null) {
109 identities.add(id);
110 }
111 } else if (element.getName().equals("feature")) {
112 if (element.getAttribute("var") != null) {
113 features.add(element.getAttribute("var"));
114 }
115 }
116 }
117 }
118
119 public List<Identity> getIdentities() {
120 return this.identities;
121 }
122
123 public List<String> getFeatures() {
124 return this.features;
125 }
126
127 public boolean hasIdentity(String category, String type) {
128 for(Identity id : this.getIdentities()) {
129 if((category == null || id.getCategory().equals(category)) &&
130 (type == null || id.getType().equals(type))) {
131 return true;
132 }
133 }
134
135 return false;
136 }
137
138 public byte[] getCapHash() {
139 StringBuilder s = new StringBuilder();
140
141 List<Identity> identities = this.getIdentities();
142 Collections.sort(identities);
143
144 for(Identity id : identities) {
145 s.append(
146 blankNull(id.getCategory()) + "/" +
147 blankNull(id.getType()) + "/" +
148 blankNull(id.getLang()) + "/" +
149 blankNull(id.getName()) + "<"
150 );
151 }
152
153 List<String> features = this.getFeatures();
154 Collections.sort(features);
155
156 for (String feature : features) {
157 s.append(feature + "<");
158 }
159
160 // TODO: data forms?
161
162 MessageDigest md;
163 try {
164 md = MessageDigest.getInstance("SHA-1");
165 } catch (NoSuchAlgorithmException e) {
166 return null;
167 }
168
169 try {
170 return md.digest(s.toString().getBytes("UTF-8"));
171 } catch(UnsupportedEncodingException e) {
172 return null;
173 }
174 }
175
176 public JSONObject toJSON() {
177 try {
178 JSONObject o = new JSONObject();
179
180 JSONArray ids = new JSONArray();
181 for(Identity id : this.getIdentities()) {
182 ids.put(id.toJSON());
183 }
184 o.put("identites", ids);
185
186 o.put("features", new JSONArray(this.getFeatures()));
187
188 return o;
189 } catch(JSONException e) {
190 return null;
191 }
192 }
193
194}