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