Contact.java

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