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