1package eu.siacs.conversations.entities;
2
3import java.util.HashSet;
4import java.util.Locale;
5import java.util.Set;
6
7import org.json.JSONArray;
8import org.json.JSONException;
9import org.json.JSONObject;
10
11import eu.siacs.conversations.xml.Element;
12import android.content.ContentValues;
13import android.database.Cursor;
14
15public class Contact implements ListItem {
16 public static final String TABLENAME = "contacts";
17
18 public static final String SYSTEMNAME = "systemname";
19 public static final String SERVERNAME = "servername";
20 public static final String JID = "jid";
21 public static final String OPTIONS = "options";
22 public static final String SYSTEMACCOUNT = "systemaccount";
23 public static final String PHOTOURI = "photouri";
24 public static final String KEYS = "pgpkey";
25 public static final String ACCOUNT = "accountUuid";
26 public static final String AVATAR = "avatar";
27 public static final String LAST_PRESENCE = "last_presence";
28 public static final String LAST_TIME = "last_time";
29
30 protected String accountUuid;
31 protected String systemName;
32 protected String serverName;
33 protected String presenceName;
34 protected String jid;
35 protected int subscription = 0;
36 protected String systemAccount;
37 protected String photoUri;
38 protected String avatar;
39 protected JSONObject keys = new JSONObject();
40 protected Presences presences = new Presences();
41
42 protected Account account;
43
44 protected boolean inRoster = true;
45
46 public Lastseen lastseen = new Lastseen();
47
48 public Contact(final String account, final String systemName, final String serverName,
49 final String jid, final int subscription, final String photoUri,
50 final String systemAccount, final String keys, final String avatar,
51 final Lastseen lastseen) {
52 this(account, systemName, serverName, jid, subscription, photoUri, systemAccount, keys,
53 avatar);
54 this.lastseen = lastseen;
55 }
56
57 public Contact(final String account, final String systemName, final String serverName,
58 final String jid, final int subscription, final String photoUri,
59 final String systemAccount, final String keys, final String avatar) {
60 this.accountUuid = account;
61 this.systemName = systemName;
62 this.serverName = serverName;
63 this.jid = jid;
64 this.subscription = subscription;
65 this.photoUri = photoUri;
66 this.systemAccount = systemAccount;
67 try {
68 this.keys = (keys == null ? new JSONObject("") : new JSONObject(keys));
69 } catch (JSONException e) {
70 this.keys = new JSONObject();
71 }
72 this.avatar = avatar;
73 }
74
75 public Contact(final String jid) {
76 this.jid = jid;
77 }
78
79 public String getDisplayName() {
80 if (this.systemName != null) {
81 return this.systemName;
82 } else if (this.serverName != null) {
83 return this.serverName;
84 } else if (this.presenceName != null) {
85 return this.presenceName;
86 } else {
87 return this.jid.split("@")[0];
88 }
89 }
90
91 public String getProfilePhoto() {
92 return this.photoUri;
93 }
94
95 public String getJid() {
96 return this.jid.toLowerCase(Locale.getDefault());
97 }
98
99 public boolean match(String needle) {
100 return needle == null
101 || jid.contains(needle.toLowerCase())
102 || getDisplayName().toLowerCase()
103 .contains(needle.toLowerCase());
104 }
105
106 public ContentValues getContentValues() {
107 ContentValues values = new ContentValues();
108 values.put(ACCOUNT, accountUuid);
109 values.put(SYSTEMNAME, systemName);
110 values.put(SERVERNAME, serverName);
111 values.put(JID, jid);
112 values.put(OPTIONS, subscription);
113 values.put(SYSTEMACCOUNT, systemAccount);
114 values.put(PHOTOURI, photoUri);
115 values.put(KEYS, keys.toString());
116 values.put(AVATAR, avatar);
117 values.put(LAST_PRESENCE, lastseen.presence);
118 values.put(LAST_TIME, lastseen.time);
119 return values;
120 }
121
122 public static Contact fromCursor(final Cursor cursor) {
123 final Lastseen lastseen = new Lastseen(
124 cursor.getString(cursor.getColumnIndex(LAST_PRESENCE)),
125 cursor.getLong(cursor.getColumnIndex(LAST_TIME)));
126 return new Contact(cursor.getString(cursor.getColumnIndex(ACCOUNT)),
127 cursor.getString(cursor.getColumnIndex(SYSTEMNAME)),
128 cursor.getString(cursor.getColumnIndex(SERVERNAME)),
129 cursor.getString(cursor.getColumnIndex(JID)),
130 cursor.getInt(cursor.getColumnIndex(OPTIONS)),
131 cursor.getString(cursor.getColumnIndex(PHOTOURI)),
132 cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT)),
133 cursor.getString(cursor.getColumnIndex(KEYS)),
134 cursor.getString(cursor.getColumnIndex(AVATAR)),
135 lastseen);
136 }
137
138 public int getSubscription() {
139 return this.subscription;
140 }
141
142 public void setSystemAccount(String account) {
143 this.systemAccount = account;
144 }
145
146 public void setAccount(Account account) {
147 this.account = account;
148 this.accountUuid = account.getUuid();
149 }
150
151 public Account getAccount() {
152 return this.account;
153 }
154
155 public Presences getPresences() {
156 return this.presences;
157 }
158
159 public void updatePresence(String resource, int status) {
160 this.presences.updatePresence(resource, status);
161 }
162
163 public void removePresence(String resource) {
164 this.presences.removePresence(resource);
165 }
166
167 public void clearPresences() {
168 this.presences.clearPresences();
169 this.resetOption(Options.PENDING_SUBSCRIPTION_REQUEST);
170 }
171
172 public int getMostAvailableStatus() {
173 return this.presences.getMostAvailableStatus();
174 }
175
176 public void setPresences(Presences pres) {
177 this.presences = pres;
178 }
179
180 public void setPhotoUri(String uri) {
181 this.photoUri = uri;
182 }
183
184 public void setServerName(String serverName) {
185 this.serverName = serverName;
186 }
187
188 public void setSystemName(String systemName) {
189 this.systemName = systemName;
190 }
191
192 public void setPresenceName(String presenceName) {
193 this.presenceName = presenceName;
194 }
195
196 public String getSystemAccount() {
197 return systemAccount;
198 }
199
200 public Set<String> getOtrFingerprints() {
201 Set<String> set = new HashSet<String>();
202 try {
203 if (this.keys.has("otr_fingerprints")) {
204 JSONArray fingerprints = this.keys
205 .getJSONArray("otr_fingerprints");
206 for (int i = 0; i < fingerprints.length(); ++i) {
207 set.add(fingerprints.getString(i));
208 }
209 }
210 } catch (JSONException e) {
211 // TODO Auto-generated catch block
212 e.printStackTrace();
213 }
214 return set;
215 }
216
217 public void addOtrFingerprint(String print) {
218 try {
219 JSONArray fingerprints;
220 if (!this.keys.has("otr_fingerprints")) {
221 fingerprints = new JSONArray();
222
223 } else {
224 fingerprints = this.keys.getJSONArray("otr_fingerprints");
225 }
226 fingerprints.put(print);
227 this.keys.put("otr_fingerprints", fingerprints);
228 } catch (JSONException e) {
229
230 }
231 }
232
233 public void setPgpKeyId(long keyId) {
234 try {
235 this.keys.put("pgp_keyid", keyId);
236 } catch (JSONException e) {
237
238 }
239 }
240
241 public long getPgpKeyId() {
242 if (this.keys.has("pgp_keyid")) {
243 try {
244 return this.keys.getLong("pgp_keyid");
245 } catch (JSONException e) {
246 return 0;
247 }
248 } else {
249 return 0;
250 }
251 }
252
253 public void setOption(int option) {
254 this.subscription |= 1 << option;
255 }
256
257 public void resetOption(int option) {
258 this.subscription &= ~(1 << option);
259 }
260
261 public boolean getOption(int option) {
262 return ((this.subscription & (1 << option)) != 0);
263 }
264
265 public boolean showInRoster() {
266 return (this.getOption(Contact.Options.IN_ROSTER) && (!this
267 .getOption(Contact.Options.DIRTY_DELETE)))
268 || (this.getOption(Contact.Options.DIRTY_PUSH));
269 }
270
271 public void parseSubscriptionFromElement(Element item) {
272 String ask = item.getAttribute("ask");
273 String subscription = item.getAttribute("subscription");
274
275 if (subscription != null) {
276 if (subscription.equals("to")) {
277 this.resetOption(Contact.Options.FROM);
278 this.setOption(Contact.Options.TO);
279 } else if (subscription.equals("from")) {
280 this.resetOption(Contact.Options.TO);
281 this.setOption(Contact.Options.FROM);
282 this.resetOption(Contact.Options.PREEMPTIVE_GRANT);
283 } else if (subscription.equals("both")) {
284 this.setOption(Contact.Options.TO);
285 this.setOption(Contact.Options.FROM);
286 this.resetOption(Contact.Options.PREEMPTIVE_GRANT);
287 } else if (subscription.equals("none")) {
288 this.resetOption(Contact.Options.FROM);
289 this.resetOption(Contact.Options.TO);
290 }
291 }
292
293 // do NOT override asking if pending push request
294 if (!this.getOption(Contact.Options.DIRTY_PUSH)) {
295 if ((ask != null) && (ask.equals("subscribe"))) {
296 this.setOption(Contact.Options.ASKING);
297 } else {
298 this.resetOption(Contact.Options.ASKING);
299 }
300 }
301 }
302
303 public Element asElement() {
304 Element item = new Element("item");
305 item.setAttribute("jid", this.jid);
306 if (this.serverName != null) {
307 item.setAttribute("name", this.serverName);
308 }
309 return item;
310 }
311
312 public class Options {
313 public static final int TO = 0;
314 public static final int FROM = 1;
315 public static final int ASKING = 2;
316 public static final int PREEMPTIVE_GRANT = 3;
317 public static final int IN_ROSTER = 4;
318 public static final int PENDING_SUBSCRIPTION_REQUEST = 5;
319 public static final int DIRTY_PUSH = 6;
320 public static final int DIRTY_DELETE = 7;
321 }
322
323 public static class Lastseen {
324 public long time;
325 public String presence;
326
327 public Lastseen() {
328 time = 0;
329 presence = null;
330 }
331 public Lastseen(final String presence, final long time) {
332 this.time = time;
333 this.presence = presence;
334 }
335 }
336
337 @Override
338 public int compareTo(ListItem another) {
339 return this.getDisplayName().compareToIgnoreCase(
340 another.getDisplayName());
341 }
342
343 public String getServer() {
344 String[] split = getJid().split("@");
345 if (split.length >= 2) {
346 return split[1];
347 } else {
348 return null;
349 }
350 }
351
352 public boolean setAvatar(String filename) {
353 if (this.avatar != null && this.avatar.equals(filename)) {
354 return false;
355 } else {
356 this.avatar = filename;
357 return true;
358 }
359 }
360
361 public String getAvatar() {
362 return this.avatar;
363 }
364
365 public boolean deleteOtrFingerprint(String fingerprint) {
366 boolean success = false;
367 try {
368 if (this.keys.has("otr_fingerprints")) {
369 JSONArray newPrints = new JSONArray();
370 JSONArray oldPrints = this.keys
371 .getJSONArray("otr_fingerprints");
372 for (int i = 0; i < oldPrints.length(); ++i) {
373 if (!oldPrints.getString(i).equals(fingerprint)) {
374 newPrints.put(oldPrints.getString(i));
375 } else {
376 success = true;
377 }
378 }
379 this.keys.put("otr_fingerprints", newPrints);
380 }
381 return success;
382 } catch (JSONException e) {
383 return false;
384 }
385 }
386
387 public boolean trusted() {
388 return getOption(Options.FROM) && getOption(Options.TO);
389 }
390}