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