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