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;
19import android.util.Log;
20
21public class Conversation extends AbstractEntity {
22
23 private static final long serialVersionUID = -6727528868973996739L;
24
25 public static final String TABLENAME = "conversations";
26
27 public static final int STATUS_AVAILABLE = 0;
28 public static final int STATUS_ARCHIVED = 1;
29 public static final int STATUS_DELETED = 2;
30
31 public static final int MODE_MULTI = 1;
32 public static final int MODE_SINGLE = 0;
33
34 public static final String NAME = "name";
35 public static final String ACCOUNT = "accountUuid";
36 public static final String CONTACT = "contactUuid";
37 public static final String CONTACTJID = "contactJid";
38 public static final String STATUS = "status";
39 public static final String CREATED = "created";
40 public static final String MODE = "mode";
41
42 private String name;
43 private String contactUuid;
44 private String accountUuid;
45 private String contactJid;
46 private int status;
47 private long created;
48 private int mode;
49
50 private String nextPresence;
51
52 private transient List<Message> messages = null;
53 private transient Account account = null;
54
55 private transient SessionImpl otrSession;
56
57 private transient String otrFingerprint = null;
58
59 private int nextMessageEncryption = -1;
60 private String nextMessage;
61
62 private transient MucOptions mucOptions = null;
63
64 private transient String latestMarkableMessageId;
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 void markRead(XmppConnectionService service) {
119 markRead();
120 if (service.confirmMessages() && this.latestMarkableMessageId != null) {
121 service.sendConfirmMessage(getAccount(), getContactJid(),
122 this.latestMarkableMessageId);
123 this.latestMarkableMessageId = null;
124 }
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 {
148 return this.getContact().getDisplayName();
149 }
150 }
151
152 public String getProfilePhotoString() {
153 return this.getContact().getProfilePhoto();
154 }
155
156 public String getAccountUuid() {
157 return this.accountUuid;
158 }
159
160 public Account getAccount() {
161 return this.account;
162 }
163
164 public Contact getContact() {
165 return this.account.getRoster().getContact(this.contactJid);
166 }
167
168 public void setAccount(Account account) {
169 this.account = account;
170 }
171
172 public String getContactJid() {
173 return this.contactJid;
174 }
175
176 public Uri getProfilePhotoUri() {
177 if (this.getProfilePhotoString() != null) {
178 return Uri.parse(this.getProfilePhotoString());
179 }
180 return null;
181 }
182
183 public int getStatus() {
184 return this.status;
185 }
186
187 public long getCreated() {
188 return this.created;
189 }
190
191 public ContentValues getContentValues() {
192 ContentValues values = new ContentValues();
193 values.put(UUID, uuid);
194 values.put(NAME, name);
195 values.put(CONTACT, contactUuid);
196 values.put(ACCOUNT, accountUuid);
197 values.put(CONTACTJID, contactJid);
198 values.put(CREATED, created);
199 values.put(STATUS, status);
200 values.put(MODE, mode);
201 return values;
202 }
203
204 public static Conversation fromCursor(Cursor cursor) {
205 return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
206 cursor.getString(cursor.getColumnIndex(NAME)),
207 cursor.getString(cursor.getColumnIndex(CONTACT)),
208 cursor.getString(cursor.getColumnIndex(ACCOUNT)),
209 cursor.getString(cursor.getColumnIndex(CONTACTJID)),
210 cursor.getLong(cursor.getColumnIndex(CREATED)),
211 cursor.getInt(cursor.getColumnIndex(STATUS)),
212 cursor.getInt(cursor.getColumnIndex(MODE)));
213 }
214
215 public void setStatus(int status) {
216 this.status = status;
217 }
218
219 public int getMode() {
220 return this.mode;
221 }
222
223 public void setMode(int mode) {
224 this.mode = mode;
225 }
226
227 public SessionImpl startOtrSession(Context context, String presence,
228 boolean sendStart) {
229 if (this.otrSession != null) {
230 return this.otrSession;
231 } else {
232 SessionID sessionId = new SessionID(this.getContactJid(), presence,
233 "xmpp");
234 this.otrSession = new SessionImpl(sessionId, getAccount()
235 .getOtrEngine(context));
236 try {
237 if (sendStart) {
238 this.otrSession.startSession();
239 return this.otrSession;
240 }
241 return this.otrSession;
242 } catch (OtrException e) {
243 return null;
244 }
245 }
246
247 }
248
249 public SessionImpl getOtrSession() {
250 return this.otrSession;
251 }
252
253 public void resetOtrSession() {
254 this.otrSession = null;
255 }
256
257 public void endOtrIfNeeded() {
258 if (this.otrSession != null) {
259 if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
260 Log.d("xmppService", "ending otr session with "
261 + getContactJid());
262 try {
263 this.otrSession.endSession();
264 this.resetOtrSession();
265 } catch (OtrException e) {
266 this.resetOtrSession();
267 }
268 }
269 }
270 }
271
272 public boolean hasValidOtrSession() {
273 return this.otrSession != null;
274 }
275
276 public String getOtrFingerprint() {
277 if (this.otrFingerprint == null) {
278 try {
279 DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
280 .getRemotePublicKey();
281 StringBuilder builder = new StringBuilder(
282 new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
283 builder.insert(8, " ");
284 builder.insert(17, " ");
285 builder.insert(26, " ");
286 builder.insert(35, " ");
287 this.otrFingerprint = builder.toString();
288 } catch (OtrCryptoException e) {
289
290 }
291 }
292 return this.otrFingerprint;
293 }
294
295 public synchronized MucOptions getMucOptions() {
296 if (this.mucOptions == null) {
297 this.mucOptions = new MucOptions(this.getAccount());
298 }
299 this.mucOptions.setConversation(this);
300 return this.mucOptions;
301 }
302
303 public void resetMucOptions() {
304 this.mucOptions = null;
305 }
306
307 public void setContactJid(String jid) {
308 this.contactJid = jid;
309 }
310
311 public void setNextPresence(String presence) {
312 this.nextPresence = presence;
313 }
314
315 public String getNextPresence() {
316 return this.nextPresence;
317 }
318
319 public int getLatestEncryption() {
320 int latestEncryption = this.getLatestMessage().getEncryption();
321 if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)
322 || (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
323 return Message.ENCRYPTION_PGP;
324 } else {
325 return latestEncryption;
326 }
327 }
328
329 public int getNextEncryption() {
330 if (this.nextMessageEncryption == -1) {
331 return this.getLatestEncryption();
332 }
333 return this.nextMessageEncryption;
334 }
335
336 public void setNextEncryption(int encryption) {
337 this.nextMessageEncryption = encryption;
338 }
339
340 public String getNextMessage() {
341 if (this.nextMessage == null) {
342 return "";
343 } else {
344 return this.nextMessage;
345 }
346 }
347
348 public void setNextMessage(String message) {
349 this.nextMessage = message;
350 }
351
352 public void setLatestMarkableMessageId(String id) {
353 if (id != null) {
354 this.latestMarkableMessageId = id;
355 }
356 }
357}