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