1package eu.siacs.conversations.entities;
2
3import java.security.interfaces.DSAPublicKey;
4import java.util.ArrayList;
5import java.util.List;
6
7import eu.siacs.conversations.services.XmppConnectionService;
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.net.Uri;
19
20public class Conversation extends AbstractEntity {
21
22 private static final long serialVersionUID = -6727528868973996739L;
23
24 public static final String TABLENAME = "conversations";
25
26 public static final int STATUS_AVAILABLE = 0;
27 public static final int STATUS_ARCHIVED = 1;
28 public static final int STATUS_DELETED = 2;
29
30 public static final int MODE_MULTI = 1;
31 public static final int MODE_SINGLE = 0;
32
33 public static final String NAME = "name";
34 public static final String ACCOUNT = "accountUuid";
35 public static final String CONTACT = "contactUuid";
36 public static final String CONTACTJID = "contactJid";
37 public static final String STATUS = "status";
38 public static final String CREATED = "created";
39 public static final String MODE = "mode";
40
41 private String name;
42 private String contactUuid;
43 private String accountUuid;
44 private String contactJid;
45 private int status;
46 private long created;
47 private int mode;
48
49 private String nextPresence;
50
51 private transient List<Message> messages = null;
52 private transient Account account = null;
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 private transient String latestMarkableMessageId;
64
65 public Conversation(String name, Account account, String contactJid,
66 int mode) {
67 this(java.util.UUID.randomUUID().toString(), name, null, account
68 .getUuid(), contactJid, System.currentTimeMillis(),
69 STATUS_AVAILABLE, mode);
70 this.account = account;
71 }
72
73 public Conversation(String uuid, String name, String contactUuid,
74 String accountUuid, String contactJid, long created, int status,
75 int mode) {
76 this.uuid = uuid;
77 this.name = name;
78 this.contactUuid = contactUuid;
79 this.accountUuid = accountUuid;
80 this.contactJid = contactJid;
81 this.created = created;
82 this.status = status;
83 this.mode = mode;
84 }
85
86 public List<Message> getMessages() {
87 if (messages == null)
88 this.messages = new ArrayList<Message>(); // prevent null pointer
89
90 // populate with Conversation (this)
91
92 for (Message msg : messages) {
93 msg.setConversation(this);
94 }
95
96 return messages;
97 }
98
99 public boolean isRead() {
100 if ((this.messages == null) || (this.messages.size() == 0))
101 return true;
102 return this.messages.get(this.messages.size() - 1).isRead();
103 }
104
105 public void markRead() {
106 if (this.messages == null) {
107 return;
108 }
109 for (int i = this.messages.size() - 1; i >= 0; --i) {
110 if (messages.get(i).isRead()) {
111 break;
112 }
113 this.messages.get(i).markRead();
114 }
115 }
116
117 public void markRead(XmppConnectionService service) {
118 markRead();
119 if (service.confirmMessages() && this.latestMarkableMessageId != null) {
120 service.sendConfirmMessage(getAccount(), getContactJid(),
121 this.latestMarkableMessageId);
122 this.latestMarkableMessageId = null;
123 }
124 }
125
126 public Message getLatestMessage() {
127 if ((this.messages == null) || (this.messages.size() == 0)) {
128 Message message = new Message(this, "", Message.ENCRYPTION_NONE);
129 message.setTime(getCreated());
130 return message;
131 } else {
132 Message message = this.messages.get(this.messages.size() - 1);
133 message.setConversation(this);
134 return message;
135 }
136 }
137
138 public void setMessages(List<Message> msgs) {
139 this.messages = msgs;
140 }
141
142 public String getName(boolean useSubject) {
143 if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null)
144 && useSubject) {
145 return getMucOptions().getSubject();
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 return this.otrSession;
239 }
240 return this.otrSession;
241 } catch (OtrException e) {
242 return null;
243 }
244 }
245
246 }
247
248 public SessionImpl getOtrSession() {
249 return this.otrSession;
250 }
251
252 public void resetOtrSession() {
253 this.otrSession = null;
254 }
255
256 public void endOtrIfNeeded() {
257 if (this.otrSession != null) {
258 if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
259 try {
260 this.otrSession.endSession();
261 this.resetOtrSession();
262 } catch (OtrException e) {
263 this.resetOtrSession();
264 }
265 } else {
266 this.resetOtrSession();
267 }
268 }
269 }
270
271 public boolean hasValidOtrSession() {
272 return this.otrSession != null;
273 }
274
275 public String getOtrFingerprint() {
276 if (this.otrFingerprint == null) {
277 try {
278 DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
279 .getRemotePublicKey();
280 StringBuilder builder = new StringBuilder(
281 new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
282 builder.insert(8, " ");
283 builder.insert(17, " ");
284 builder.insert(26, " ");
285 builder.insert(35, " ");
286 this.otrFingerprint = builder.toString();
287 } catch (OtrCryptoException e) {
288
289 }
290 }
291 return this.otrFingerprint;
292 }
293
294 public synchronized MucOptions getMucOptions() {
295 if (this.mucOptions == null) {
296 this.mucOptions = new MucOptions(this.getAccount());
297 }
298 this.mucOptions.setConversation(this);
299 return this.mucOptions;
300 }
301
302 public void resetMucOptions() {
303 this.mucOptions = null;
304 }
305
306 public void setContactJid(String jid) {
307 this.contactJid = jid;
308 }
309
310 public void setNextPresence(String presence) {
311 this.nextPresence = presence;
312 }
313
314 public String getNextPresence() {
315 return this.nextPresence;
316 }
317
318 public int getLatestEncryption() {
319 int latestEncryption = this.getLatestMessage().getEncryption();
320 if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)
321 || (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
322 return Message.ENCRYPTION_PGP;
323 } else {
324 return latestEncryption;
325 }
326 }
327
328 public int getNextEncryption() {
329 if (this.nextMessageEncryption == -1) {
330 return this.getLatestEncryption();
331 }
332 return this.nextMessageEncryption;
333 }
334
335 public void setNextEncryption(int encryption) {
336 this.nextMessageEncryption = encryption;
337 }
338
339 public String getNextMessage() {
340 if (this.nextMessage == null) {
341 return "";
342 } else {
343 return this.nextMessage;
344 }
345 }
346
347 public void setNextMessage(String message) {
348 this.nextMessage = message;
349 }
350
351 public void setLatestMarkableMessageId(String id) {
352 if (id != null) {
353 this.latestMarkableMessageId = id;
354 }
355 }
356}