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