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;
18import android.util.Log;
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 private transient Contact contact;
54
55 private transient SessionImpl otrSession;
56
57 private transient String otrFingerprint = null;
58
59 public int nextMessageEncryption = Message.ENCRYPTION_NONE;
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 Log.d("xmppServic", "couldnt start otr");
241 return null;
242 }
243 }
244
245 }
246
247 public SessionImpl getOtrSession() {
248 return this.otrSession;
249 }
250
251 public void resetOtrSession() {
252 this.otrSession = null;
253 }
254
255 public void endOtrIfNeeded() {
256 if (this.otrSession != null) {
257 if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
258 try {
259 this.otrSession.endSession();
260 this.resetOtrSession();
261 } catch (OtrException e) {
262 this.resetOtrSession();
263 }
264 }
265 }
266 }
267
268 public boolean hasValidOtrSession() {
269 if (this.otrSession == null) {
270 return false;
271 } else {
272 String foreignPresence = this.otrSession.getSessionID().getUserID();
273 if (!getContact().getPresences().containsKey(foreignPresence)) {
274 this.resetOtrSession();
275 return false;
276 }
277 return true;
278 }
279 }
280
281 public String getOtrFingerprint() {
282 if (this.otrFingerprint == null) {
283 try {
284 DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
285 .getRemotePublicKey();
286 StringBuilder builder = new StringBuilder(
287 new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
288 builder.insert(8, " ");
289 builder.insert(17, " ");
290 builder.insert(26, " ");
291 builder.insert(35, " ");
292 this.otrFingerprint = builder.toString();
293 } catch (OtrCryptoException e) {
294
295 }
296 }
297 return this.otrFingerprint;
298 }
299
300 public synchronized MucOptions getMucOptions() {
301 if (this.mucOptions == null) {
302 this.mucOptions = new MucOptions();
303 }
304 this.mucOptions.setConversation(this);
305 return this.mucOptions;
306 }
307
308 public void resetMucOptions() {
309 this.mucOptions = null;
310 }
311
312 public void setContactJid(String jid) {
313 this.contactJid = jid;
314 }
315
316 public void setNextPresence(String presence) {
317 this.nextPresence = presence;
318 }
319
320 public String getNextPresence() {
321 return this.nextPresence;
322 }
323}