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