Conversation.java

  1package eu.siacs.conversations.entities;
  2
  3import java.security.interfaces.DSAPublicKey;
  4import java.util.List;
  5import java.util.concurrent.CopyOnWriteArrayList;
  6
  7import eu.siacs.conversations.utils.UIHelper;
  8
  9import net.java.otr4j.OtrException;
 10import net.java.otr4j.crypto.OtrCryptoEngineImpl;
 11import net.java.otr4j.crypto.OtrCryptoException;
 12import net.java.otr4j.session.SessionID;
 13import net.java.otr4j.session.SessionImpl;
 14import net.java.otr4j.session.SessionStatus;
 15import android.content.ContentValues;
 16import android.content.Context;
 17import android.database.Cursor;
 18import android.graphics.Bitmap;
 19
 20public class Conversation extends AbstractEntity {
 21	public static final String TABLENAME = "conversations";
 22
 23	public static final int STATUS_AVAILABLE = 0;
 24	public static final int STATUS_ARCHIVED = 1;
 25	public static final int STATUS_DELETED = 2;
 26
 27	public static final int MODE_MULTI = 1;
 28	public static final int MODE_SINGLE = 0;
 29
 30	public static final String NAME = "name";
 31	public static final String ACCOUNT = "accountUuid";
 32	public static final String CONTACT = "contactUuid";
 33	public static final String CONTACTJID = "contactJid";
 34	public static final String STATUS = "status";
 35	public static final String CREATED = "created";
 36	public static final String MODE = "mode";
 37
 38	private String name;
 39	private String contactUuid;
 40	private String accountUuid;
 41	private String contactJid;
 42	private int status;
 43	private long created;
 44	private int mode;
 45
 46	private String nextPresence;
 47
 48	private transient CopyOnWriteArrayList<Message> messages = null;
 49	private transient Account account = null;
 50
 51	private transient SessionImpl otrSession;
 52
 53	private transient String otrFingerprint = null;
 54
 55	private int nextMessageEncryption = -1;
 56	private String nextMessage;
 57
 58	private transient MucOptions mucOptions = null;
 59
 60	private transient String latestMarkableMessageId;
 61
 62	private byte[] symmetricKey;
 63
 64	private boolean otrSessionNeedsStarting = false;
 65
 66	private Bookmark bookmark;
 67
 68	public Conversation(String name, Account account, String contactJid,
 69			int mode) {
 70		this(java.util.UUID.randomUUID().toString(), name, null, account
 71				.getUuid(), contactJid, System.currentTimeMillis(),
 72				STATUS_AVAILABLE, mode);
 73		this.account = account;
 74	}
 75
 76	public Conversation(String uuid, String name, String contactUuid,
 77			String accountUuid, String contactJid, long created, int status,
 78			int mode) {
 79		this.uuid = uuid;
 80		this.name = name;
 81		this.contactUuid = contactUuid;
 82		this.accountUuid = accountUuid;
 83		this.contactJid = contactJid;
 84		this.created = created;
 85		this.status = status;
 86		this.mode = mode;
 87	}
 88
 89	public List<Message> getMessages() {
 90		if (messages == null) {
 91			this.messages = new CopyOnWriteArrayList<Message>(); // prevent null
 92																	// pointer
 93		}
 94
 95		// populate with Conversation (this)
 96
 97		for (Message msg : messages) {
 98			msg.setConversation(this);
 99		}
100
101		return messages;
102	}
103
104	public boolean isRead() {
105		if ((this.messages == null) || (this.messages.size() == 0))
106			return true;
107		return this.messages.get(this.messages.size() - 1).isRead();
108	}
109
110	public void markRead() {
111		if (this.messages == null) {
112			return;
113		}
114		for (int i = this.messages.size() - 1; i >= 0; --i) {
115			if (messages.get(i).isRead()) {
116				break;
117			}
118			this.messages.get(i).markRead();
119		}
120	}
121
122	public String popLatestMarkableMessageId() {
123		String id = this.latestMarkableMessageId;
124		this.latestMarkableMessageId = null;
125		return id;
126	}
127
128	public Message getLatestMessage() {
129		if ((this.messages == null) || (this.messages.size() == 0)) {
130			Message message = new Message(this, "", Message.ENCRYPTION_NONE);
131			message.setTime(getCreated());
132			return message;
133		} else {
134			Message message = this.messages.get(this.messages.size() - 1);
135			message.setConversation(this);
136			return message;
137		}
138	}
139
140	public void setMessages(CopyOnWriteArrayList<Message> msgs) {
141		this.messages = msgs;
142	}
143
144	public String getName(boolean useSubject) {
145		if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null)
146				&& useSubject) {
147			return getMucOptions().getSubject();
148		} else if (getMode() == MODE_MULTI && bookmark != null
149				&& bookmark.getName() != null) {
150			return bookmark.getName();
151		} else {
152			return this.getContact().getDisplayName();
153		}
154	}
155
156	public String getProfilePhotoString() {
157		return this.getContact().getProfilePhoto();
158	}
159
160	public String getAccountUuid() {
161		return this.accountUuid;
162	}
163
164	public Account getAccount() {
165		return this.account;
166	}
167
168	public Contact getContact() {
169		return this.account.getRoster().getContact(this.contactJid);
170	}
171
172	public void setAccount(Account account) {
173		this.account = account;
174	}
175
176	public String getContactJid() {
177		return this.contactJid;
178	}
179
180	public int getStatus() {
181		return this.status;
182	}
183
184	public long getCreated() {
185		return this.created;
186	}
187
188	public ContentValues getContentValues() {
189		ContentValues values = new ContentValues();
190		values.put(UUID, uuid);
191		values.put(NAME, name);
192		values.put(CONTACT, contactUuid);
193		values.put(ACCOUNT, accountUuid);
194		values.put(CONTACTJID, contactJid);
195		values.put(CREATED, created);
196		values.put(STATUS, status);
197		values.put(MODE, mode);
198		return values;
199	}
200
201	public static Conversation fromCursor(Cursor cursor) {
202		return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
203				cursor.getString(cursor.getColumnIndex(NAME)),
204				cursor.getString(cursor.getColumnIndex(CONTACT)),
205				cursor.getString(cursor.getColumnIndex(ACCOUNT)),
206				cursor.getString(cursor.getColumnIndex(CONTACTJID)),
207				cursor.getLong(cursor.getColumnIndex(CREATED)),
208				cursor.getInt(cursor.getColumnIndex(STATUS)),
209				cursor.getInt(cursor.getColumnIndex(MODE)));
210	}
211
212	public void setStatus(int status) {
213		this.status = status;
214	}
215
216	public int getMode() {
217		return this.mode;
218	}
219
220	public void setMode(int mode) {
221		this.mode = mode;
222	}
223
224	public SessionImpl startOtrSession(Context context, String presence,
225			boolean sendStart) {
226		if (this.otrSession != null) {
227			return this.otrSession;
228		} else {
229			SessionID sessionId = new SessionID(this.getContactJid(), presence,
230					"xmpp");
231			this.otrSession = new SessionImpl(sessionId, getAccount()
232					.getOtrEngine(context));
233			try {
234				if (sendStart) {
235					this.otrSession.startSession();
236					this.otrSessionNeedsStarting = false;
237					return this.otrSession;
238				} else {
239					this.otrSessionNeedsStarting = true;
240				}
241				return this.otrSession;
242			} catch (OtrException e) {
243				return null;
244			}
245		}
246
247	}
248
249	public SessionImpl getOtrSession() {
250		return this.otrSession;
251	}
252
253	public void resetOtrSession() {
254		this.otrFingerprint = null;
255		this.otrSessionNeedsStarting = false;
256		this.otrSession = null;
257	}
258
259	public void startOtrIfNeeded() {
260		if (this.otrSession != null && this.otrSessionNeedsStarting) {
261			try {
262				this.otrSession.startSession();
263			} catch (OtrException e) {
264				this.resetOtrSession();
265			}
266		}
267	}
268
269	public void endOtrIfNeeded() {
270		if (this.otrSession != null) {
271			if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
272				try {
273					this.otrSession.endSession();
274					this.resetOtrSession();
275				} catch (OtrException e) {
276					this.resetOtrSession();
277				}
278			} else {
279				this.resetOtrSession();
280			}
281		}
282	}
283
284	public boolean hasValidOtrSession() {
285		return this.otrSession != null;
286	}
287
288	public String getOtrFingerprint() {
289		if (this.otrFingerprint == null) {
290			try {
291				if (getOtrSession() == null) {
292					return "";
293				}
294				DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
295						.getRemotePublicKey();
296				StringBuilder builder = new StringBuilder(
297						new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
298				builder.insert(8, " ");
299				builder.insert(17, " ");
300				builder.insert(26, " ");
301				builder.insert(35, " ");
302				this.otrFingerprint = builder.toString();
303			} catch (OtrCryptoException e) {
304
305			}
306		}
307		return this.otrFingerprint;
308	}
309
310	public synchronized MucOptions getMucOptions() {
311		if (this.mucOptions == null) {
312			this.mucOptions = new MucOptions(this.getAccount());
313		}
314		this.mucOptions.setConversation(this);
315		return this.mucOptions;
316	}
317
318	public void resetMucOptions() {
319		this.mucOptions = null;
320	}
321
322	public void setContactJid(String jid) {
323		this.contactJid = jid;
324	}
325
326	public void setNextPresence(String presence) {
327		this.nextPresence = presence;
328	}
329
330	public String getNextPresence() {
331		return this.nextPresence;
332	}
333
334	public int getLatestEncryption() {
335		int latestEncryption = this.getLatestMessage().getEncryption();
336		if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)
337				|| (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
338			return Message.ENCRYPTION_PGP;
339		} else if (latestEncryption == Message.ENCRYPTION_NONE) {
340			if (getContact().getPresences().size() == 1) {
341				if (getContact().getOtrFingerprints().size() >= 1) {
342					return Message.ENCRYPTION_OTR;
343				} else {
344					return latestEncryption;
345				}
346			} else {
347				return latestEncryption;
348			}
349		} else {
350			return latestEncryption;
351		}
352	}
353
354	public int getNextEncryption() {
355		if (this.nextMessageEncryption == -1) {
356			return this.getLatestEncryption();
357		}
358		return this.nextMessageEncryption;
359	}
360
361	public void setNextEncryption(int encryption) {
362		this.nextMessageEncryption = encryption;
363	}
364
365	public String getNextMessage() {
366		if (this.nextMessage == null) {
367			return "";
368		} else {
369			return this.nextMessage;
370		}
371	}
372
373	public void setNextMessage(String message) {
374		this.nextMessage = message;
375	}
376
377	public void setLatestMarkableMessageId(String id) {
378		if (id != null) {
379			this.latestMarkableMessageId = id;
380		}
381	}
382
383	public void setSymmetricKey(byte[] key) {
384		this.symmetricKey = key;
385	}
386
387	public byte[] getSymmetricKey() {
388		return this.symmetricKey;
389	}
390
391	public void setBookmark(Bookmark bookmark) {
392		this.bookmark = bookmark;
393		this.bookmark.setConversation(this);
394	}
395
396	public void deregisterWithBookmark() {
397		if (this.bookmark != null) {
398			this.bookmark.setConversation(null);
399		}
400	}
401
402	public Bookmark getBookmark() {
403		return this.bookmark;
404	}
405
406	public Bitmap getImage(Context context, int size) {
407		if (mode == MODE_SINGLE) {
408			return getContact().getImage(size, context);
409		} else {
410			return UIHelper.getContactPicture(this, size, context, false);
411		}
412	}
413
414	public boolean hasDuplicateMessage(Message message) {
415		for (int i = this.getMessages().size() - 1; i >= 0; --i) {
416			if (this.messages.get(i).equals(message)) {
417				return true;
418			}
419		}
420		return false;
421	}
422}