1package eu.siacs.conversations.entities;
2
3import android.content.ContentValues;
4import android.database.Cursor;
5
6import java.net.MalformedURLException;
7import java.net.URL;
8import java.util.Arrays;
9
10import eu.siacs.conversations.Config;
11import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
12import eu.siacs.conversations.utils.GeoHelper;
13import eu.siacs.conversations.utils.MimeUtils;
14import eu.siacs.conversations.utils.UIHelper;
15import eu.siacs.conversations.xmpp.jid.InvalidJidException;
16import eu.siacs.conversations.xmpp.jid.Jid;
17
18public class Message extends AbstractEntity {
19
20 public static final String TABLENAME = "messages";
21
22 public static final String MERGE_SEPARATOR = " \u200B\n\n";
23
24 public static final int STATUS_RECEIVED = 0;
25 public static final int STATUS_UNSEND = 1;
26 public static final int STATUS_SEND = 2;
27 public static final int STATUS_SEND_FAILED = 3;
28 public static final int STATUS_WAITING = 5;
29 public static final int STATUS_OFFERED = 6;
30 public static final int STATUS_SEND_RECEIVED = 7;
31 public static final int STATUS_SEND_DISPLAYED = 8;
32
33 public static final int ENCRYPTION_NONE = 0;
34 public static final int ENCRYPTION_PGP = 1;
35 public static final int ENCRYPTION_OTR = 2;
36 public static final int ENCRYPTION_DECRYPTED = 3;
37 public static final int ENCRYPTION_DECRYPTION_FAILED = 4;
38 public static final int ENCRYPTION_AXOLOTL = 5;
39
40 public static final int TYPE_TEXT = 0;
41 public static final int TYPE_IMAGE = 1;
42 public static final int TYPE_FILE = 2;
43 public static final int TYPE_STATUS = 3;
44 public static final int TYPE_PRIVATE = 4;
45
46 public static final String CONVERSATION = "conversationUuid";
47 public static final String COUNTERPART = "counterpart";
48 public static final String TRUE_COUNTERPART = "trueCounterpart";
49 public static final String BODY = "body";
50 public static final String TIME_SENT = "timeSent";
51 public static final String ENCRYPTION = "encryption";
52 public static final String STATUS = "status";
53 public static final String TYPE = "type";
54 public static final String CARBON = "carbon";
55 public static final String EDITED = "edited";
56 public static final String REMOTE_MSG_ID = "remoteMsgId";
57 public static final String SERVER_MSG_ID = "serverMsgId";
58 public static final String RELATIVE_FILE_PATH = "relativeFilePath";
59 public static final String FINGERPRINT = "axolotl_fingerprint";
60 public static final String READ = "read";
61 public static final String ME_COMMAND = "/me ";
62
63
64 public boolean markable = false;
65 protected String conversationUuid;
66 protected Jid counterpart;
67 protected Jid trueCounterpart;
68 protected String body;
69 protected String encryptedBody;
70 protected long timeSent;
71 protected int encryption;
72 protected int status;
73 protected int type;
74 protected boolean carbon = false;
75 protected String edited = null;
76 protected String relativeFilePath;
77 protected boolean read = true;
78 protected String remoteMsgId = null;
79 protected String serverMsgId = null;
80 protected Conversation conversation = null;
81 protected Transferable transferable = null;
82 private Message mNextMessage = null;
83 private Message mPreviousMessage = null;
84 private String axolotlFingerprint = null;
85
86 private Message() {
87
88 }
89
90 public Message(Conversation conversation, String body, int encryption) {
91 this(conversation, body, encryption, STATUS_UNSEND);
92 }
93
94 public Message(Conversation conversation, String body, int encryption, int status) {
95 this(java.util.UUID.randomUUID().toString(),
96 conversation.getUuid(),
97 conversation.getJid() == null ? null : conversation.getJid().toBareJid(),
98 null,
99 body,
100 System.currentTimeMillis(),
101 encryption,
102 status,
103 TYPE_TEXT,
104 false,
105 null,
106 null,
107 null,
108 null,
109 true,
110 null);
111 this.conversation = conversation;
112 }
113
114 private Message(final String uuid, final String conversationUUid, final Jid counterpart,
115 final Jid trueCounterpart, final String body, final long timeSent,
116 final int encryption, final int status, final int type, final boolean carbon,
117 final String remoteMsgId, final String relativeFilePath,
118 final String serverMsgId, final String fingerprint, final boolean read,
119 final String edited) {
120 this.uuid = uuid;
121 this.conversationUuid = conversationUUid;
122 this.counterpart = counterpart;
123 this.trueCounterpart = trueCounterpart;
124 this.body = body;
125 this.timeSent = timeSent;
126 this.encryption = encryption;
127 this.status = status;
128 this.type = type;
129 this.carbon = carbon;
130 this.remoteMsgId = remoteMsgId;
131 this.relativeFilePath = relativeFilePath;
132 this.serverMsgId = serverMsgId;
133 this.axolotlFingerprint = fingerprint;
134 this.read = read;
135 this.edited = edited;
136 }
137
138 public static Message fromCursor(Cursor cursor) {
139 Jid jid;
140 try {
141 String value = cursor.getString(cursor.getColumnIndex(COUNTERPART));
142 if (value != null) {
143 jid = Jid.fromString(value, true);
144 } else {
145 jid = null;
146 }
147 } catch (InvalidJidException e) {
148 jid = null;
149 }
150 Jid trueCounterpart;
151 try {
152 String value = cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART));
153 if (value != null) {
154 trueCounterpart = Jid.fromString(value, true);
155 } else {
156 trueCounterpart = null;
157 }
158 } catch (InvalidJidException e) {
159 trueCounterpart = null;
160 }
161 return new Message(cursor.getString(cursor.getColumnIndex(UUID)),
162 cursor.getString(cursor.getColumnIndex(CONVERSATION)),
163 jid,
164 trueCounterpart,
165 cursor.getString(cursor.getColumnIndex(BODY)),
166 cursor.getLong(cursor.getColumnIndex(TIME_SENT)),
167 cursor.getInt(cursor.getColumnIndex(ENCRYPTION)),
168 cursor.getInt(cursor.getColumnIndex(STATUS)),
169 cursor.getInt(cursor.getColumnIndex(TYPE)),
170 cursor.getInt(cursor.getColumnIndex(CARBON)) > 0,
171 cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)),
172 cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)),
173 cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)),
174 cursor.getString(cursor.getColumnIndex(FINGERPRINT)),
175 cursor.getInt(cursor.getColumnIndex(READ)) > 0,
176 cursor.getString(cursor.getColumnIndex(EDITED)));
177 }
178
179 public static Message createStatusMessage(Conversation conversation, String body) {
180 final Message message = new Message();
181 message.setType(Message.TYPE_STATUS);
182 message.setConversation(conversation);
183 message.setBody(body);
184 return message;
185 }
186
187 public static Message createLoadMoreMessage(Conversation conversation) {
188 final Message message = new Message();
189 message.setType(Message.TYPE_STATUS);
190 message.setConversation(conversation);
191 message.setBody("LOAD_MORE");
192 return message;
193 }
194
195 @Override
196 public ContentValues getContentValues() {
197 ContentValues values = new ContentValues();
198 values.put(UUID, uuid);
199 values.put(CONVERSATION, conversationUuid);
200 if (counterpart == null) {
201 values.putNull(COUNTERPART);
202 } else {
203 values.put(COUNTERPART, counterpart.toString());
204 }
205 if (trueCounterpart == null) {
206 values.putNull(TRUE_COUNTERPART);
207 } else {
208 values.put(TRUE_COUNTERPART, trueCounterpart.toString());
209 }
210 values.put(BODY, body);
211 values.put(TIME_SENT, timeSent);
212 values.put(ENCRYPTION, encryption);
213 values.put(STATUS, status);
214 values.put(TYPE, type);
215 values.put(CARBON, carbon ? 1 : 0);
216 values.put(REMOTE_MSG_ID, remoteMsgId);
217 values.put(RELATIVE_FILE_PATH, relativeFilePath);
218 values.put(SERVER_MSG_ID, serverMsgId);
219 values.put(FINGERPRINT, axolotlFingerprint);
220 values.put(READ,read ? 1 : 0);
221 values.put(EDITED, edited);
222 return values;
223 }
224
225 public String getConversationUuid() {
226 return conversationUuid;
227 }
228
229 public Conversation getConversation() {
230 return this.conversation;
231 }
232
233 public void setConversation(Conversation conv) {
234 this.conversation = conv;
235 }
236
237 public Jid getCounterpart() {
238 return counterpart;
239 }
240
241 public void setCounterpart(final Jid counterpart) {
242 this.counterpart = counterpart;
243 }
244
245 public Contact getContact() {
246 if (this.conversation.getMode() == Conversation.MODE_SINGLE) {
247 return this.conversation.getContact();
248 } else {
249 if (this.trueCounterpart == null) {
250 return null;
251 } else {
252 return this.conversation.getAccount().getRoster()
253 .getContactFromRoster(this.trueCounterpart);
254 }
255 }
256 }
257
258 public String getBody() {
259 return body;
260 }
261
262 public void setBody(String body) {
263 this.body = body;
264 }
265
266 public long getTimeSent() {
267 return timeSent;
268 }
269
270 public int getEncryption() {
271 return encryption;
272 }
273
274 public void setEncryption(int encryption) {
275 this.encryption = encryption;
276 }
277
278 public int getStatus() {
279 return status;
280 }
281
282 public void setStatus(int status) {
283 this.status = status;
284 }
285
286 public String getRelativeFilePath() {
287 return this.relativeFilePath;
288 }
289
290 public void setRelativeFilePath(String path) {
291 this.relativeFilePath = path;
292 }
293
294 public String getRemoteMsgId() {
295 return this.remoteMsgId;
296 }
297
298 public void setRemoteMsgId(String id) {
299 this.remoteMsgId = id;
300 }
301
302 public String getServerMsgId() {
303 return this.serverMsgId;
304 }
305
306 public void setServerMsgId(String id) {
307 this.serverMsgId = id;
308 }
309
310 public boolean isRead() {
311 return this.read;
312 }
313
314 public void markRead() {
315 this.read = true;
316 }
317
318 public void markUnread() {
319 this.read = false;
320 }
321
322 public void setTime(long time) {
323 this.timeSent = time;
324 }
325
326 public String getEncryptedBody() {
327 return this.encryptedBody;
328 }
329
330 public void setEncryptedBody(String body) {
331 this.encryptedBody = body;
332 }
333
334 public int getType() {
335 return this.type;
336 }
337
338 public void setType(int type) {
339 this.type = type;
340 }
341
342 public boolean isCarbon() {
343 return carbon;
344 }
345
346 public void setCarbon(boolean carbon) {
347 this.carbon = carbon;
348 }
349
350 public void setEdited(String edited) {
351 this.edited = edited;
352 }
353
354 public boolean edited() {
355 return this.edited != null;
356 }
357
358 public void setTrueCounterpart(Jid trueCounterpart) {
359 this.trueCounterpart = trueCounterpart;
360 }
361
362 public Jid getTrueCounterpart() {
363 return this.trueCounterpart;
364 }
365
366 public Transferable getTransferable() {
367 return this.transferable;
368 }
369
370 public void setTransferable(Transferable transferable) {
371 this.transferable = transferable;
372 }
373
374 public boolean equals(Message message) {
375 if (this.serverMsgId != null && message.getServerMsgId() != null) {
376 return this.serverMsgId.equals(message.getServerMsgId());
377 } else if (this.body == null || this.counterpart == null) {
378 return false;
379 } else {
380 String body, otherBody;
381 if (this.hasFileOnRemoteHost()) {
382 body = getFileParams().url.toString();
383 otherBody = message.body == null ? null : message.body.trim();
384 } else {
385 body = this.body;
386 otherBody = message.body;
387 }
388 if (message.getRemoteMsgId() != null) {
389 return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid))
390 && this.counterpart.equals(message.getCounterpart())
391 && (body.equals(otherBody)
392 ||(message.getEncryption() == Message.ENCRYPTION_PGP
393 && message.getRemoteMsgId().matches("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"))) ;
394 } else {
395 return this.remoteMsgId == null
396 && this.counterpart.equals(message.getCounterpart())
397 && body.equals(otherBody)
398 && Math.abs(this.getTimeSent() - message.getTimeSent()) < Config.MESSAGE_MERGE_WINDOW * 1000;
399 }
400 }
401 }
402
403 public Message next() {
404 synchronized (this.conversation.messages) {
405 if (this.mNextMessage == null) {
406 int index = this.conversation.messages.indexOf(this);
407 if (index < 0 || index >= this.conversation.messages.size() - 1) {
408 this.mNextMessage = null;
409 } else {
410 this.mNextMessage = this.conversation.messages.get(index + 1);
411 }
412 }
413 return this.mNextMessage;
414 }
415 }
416
417 public Message prev() {
418 synchronized (this.conversation.messages) {
419 if (this.mPreviousMessage == null) {
420 int index = this.conversation.messages.indexOf(this);
421 if (index <= 0 || index > this.conversation.messages.size()) {
422 this.mPreviousMessage = null;
423 } else {
424 this.mPreviousMessage = this.conversation.messages.get(index - 1);
425 }
426 }
427 return this.mPreviousMessage;
428 }
429 }
430
431 public boolean isLastCorrectableMessage() {
432 Message next = next();
433 while(next != null) {
434 if (next.isCorrectable()) {
435 return false;
436 }
437 next = next.next();
438 }
439 return isCorrectable();
440 }
441
442 private boolean isCorrectable() {
443 return getStatus() != STATUS_RECEIVED && !isCarbon();
444 }
445
446 public boolean mergeable(final Message message) {
447 return message != null &&
448 (message.getType() == Message.TYPE_TEXT &&
449 this.getTransferable() == null &&
450 message.getTransferable() == null &&
451 message.getEncryption() != Message.ENCRYPTION_PGP &&
452 this.getType() == message.getType() &&
453 //this.getStatus() == message.getStatus() &&
454 isStatusMergeable(this.getStatus(), message.getStatus()) &&
455 this.getEncryption() == message.getEncryption() &&
456 this.getCounterpart() != null &&
457 this.getCounterpart().equals(message.getCounterpart()) &&
458 this.edited() == message.edited() &&
459 (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
460 !GeoHelper.isGeoUri(message.getBody()) &&
461 !GeoHelper.isGeoUri(this.body) &&
462 message.treatAsDownloadable() == Decision.NEVER &&
463 this.treatAsDownloadable() == Decision.NEVER &&
464 !message.getBody().startsWith(ME_COMMAND) &&
465 !this.getBody().startsWith(ME_COMMAND) &&
466 !this.bodyIsHeart() &&
467 !message.bodyIsHeart() &&
468 this.isTrusted() == message.isTrusted()
469 );
470 }
471
472 private static boolean isStatusMergeable(int a, int b) {
473 return a == b || (
474 (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_UNSEND)
475 || (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_SEND)
476 || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND)
477 || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND_RECEIVED)
478 || (a == Message.STATUS_SEND && b == Message.STATUS_UNSEND)
479 || (a == Message.STATUS_SEND && b == Message.STATUS_SEND_RECEIVED)
480 );
481 }
482
483 public String getMergedBody() {
484 StringBuilder body = new StringBuilder(this.body.trim());
485 Message current = this;
486 while(current.mergeable(current.next())) {
487 current = current.next();
488 body.append(MERGE_SEPARATOR);
489 body.append(current.getBody().trim());
490 }
491 return body.toString();
492 }
493
494 public boolean hasMeCommand() {
495 return getMergedBody().startsWith(ME_COMMAND);
496 }
497
498 public int getMergedStatus() {
499 int status = this.status;
500 Message current = this;
501 while(current.mergeable(current.next())) {
502 current = current.next();
503 status = current.status;
504 }
505 return status;
506 }
507
508 public long getMergedTimeSent() {
509 long time = this.timeSent;
510 Message current = this;
511 while(current.mergeable(current.next())) {
512 current = current.next();
513 time = current.timeSent;
514 }
515 return time;
516 }
517
518 public boolean wasMergedIntoPrevious() {
519 Message prev = this.prev();
520 return prev != null && prev.mergeable(this);
521 }
522
523 public boolean trusted() {
524 Contact contact = this.getContact();
525 return (status > STATUS_RECEIVED || (contact != null && contact.trusted()));
526 }
527
528 public boolean fixCounterpart() {
529 Presences presences = conversation.getContact().getPresences();
530 if (counterpart != null && presences.has(counterpart.getResourcepart())) {
531 return true;
532 } else if (presences.size() >= 1) {
533 try {
534 counterpart = Jid.fromParts(conversation.getJid().getLocalpart(),
535 conversation.getJid().getDomainpart(),
536 presences.asStringArray()[0]);
537 return true;
538 } catch (InvalidJidException e) {
539 counterpart = null;
540 return false;
541 }
542 } else {
543 counterpart = null;
544 return false;
545 }
546 }
547
548 public void setUuid(String uuid) {
549 this.uuid = uuid;
550 }
551
552 public String getEditedId() {
553 return edited;
554 }
555
556 public enum Decision {
557 MUST,
558 SHOULD,
559 NEVER,
560 }
561
562 private static String extractRelevantExtension(URL url) {
563 String path = url.getPath();
564 return extractRelevantExtension(path);
565 }
566
567 private static String extractRelevantExtension(String path) {
568 if (path == null || path.isEmpty()) {
569 return null;
570 }
571
572 String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
573 int dotPosition = filename.lastIndexOf(".");
574
575 if (dotPosition != -1) {
576 String extension = filename.substring(dotPosition + 1);
577 // we want the real file extension, not the crypto one
578 if (Arrays.asList(Transferable.VALID_CRYPTO_EXTENSIONS).contains(extension)) {
579 return extractRelevantExtension(filename.substring(0,dotPosition));
580 } else {
581 return extension;
582 }
583 }
584 return null;
585 }
586
587 public String getMimeType() {
588 if (relativeFilePath != null) {
589 int start = relativeFilePath.lastIndexOf('.') + 1;
590 if (start < relativeFilePath.length()) {
591 return MimeUtils.guessMimeTypeFromExtension(relativeFilePath.substring(start));
592 } else {
593 return null;
594 }
595 } else {
596 try {
597 return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim())));
598 } catch (MalformedURLException e) {
599 return null;
600 }
601 }
602 }
603
604 public Decision treatAsDownloadable() {
605 if (body.trim().contains(" ")) {
606 return Decision.NEVER;
607 }
608 try {
609 URL url = new URL(body);
610 if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) {
611 return Decision.NEVER;
612 }
613 String extension = extractRelevantExtension(url);
614 if (extension == null) {
615 return Decision.NEVER;
616 }
617 String ref = url.getRef();
618 boolean encrypted = ref != null && ref.matches("([A-Fa-f0-9]{2}){48}");
619
620 if (encrypted) {
621 if (MimeUtils.guessMimeTypeFromExtension(extension) != null) {
622 return Decision.MUST;
623 } else {
624 return Decision.NEVER;
625 }
626 } else if (Arrays.asList(Transferable.VALID_IMAGE_EXTENSIONS).contains(extension)
627 || Arrays.asList(Transferable.WELL_KNOWN_EXTENSIONS).contains(extension)) {
628 return Decision.SHOULD;
629 } else {
630 return Decision.NEVER;
631 }
632
633 } catch (MalformedURLException e) {
634 return Decision.NEVER;
635 }
636 }
637
638 public boolean bodyIsHeart() {
639 return body != null && UIHelper.HEARTS.contains(body.trim());
640 }
641
642 public FileParams getFileParams() {
643 FileParams params = getLegacyFileParams();
644 if (params != null) {
645 return params;
646 }
647 params = new FileParams();
648 if (this.transferable != null) {
649 params.size = this.transferable.getFileSize();
650 }
651 if (body == null) {
652 return params;
653 }
654 String parts[] = body.split("\\|");
655 switch (parts.length) {
656 case 1:
657 try {
658 params.size = Long.parseLong(parts[0]);
659 } catch (NumberFormatException e) {
660 try {
661 params.url = new URL(parts[0]);
662 } catch (MalformedURLException e1) {
663 params.url = null;
664 }
665 }
666 break;
667 case 2:
668 case 4:
669 try {
670 params.url = new URL(parts[0]);
671 } catch (MalformedURLException e1) {
672 params.url = null;
673 }
674 try {
675 params.size = Long.parseLong(parts[1]);
676 } catch (NumberFormatException e) {
677 params.size = 0;
678 }
679 try {
680 params.width = Integer.parseInt(parts[2]);
681 } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
682 params.width = 0;
683 }
684 try {
685 params.height = Integer.parseInt(parts[3]);
686 } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
687 params.height = 0;
688 }
689 break;
690 case 3:
691 try {
692 params.size = Long.parseLong(parts[0]);
693 } catch (NumberFormatException e) {
694 params.size = 0;
695 }
696 try {
697 params.width = Integer.parseInt(parts[1]);
698 } catch (NumberFormatException e) {
699 params.width = 0;
700 }
701 try {
702 params.height = Integer.parseInt(parts[2]);
703 } catch (NumberFormatException e) {
704 params.height = 0;
705 }
706 break;
707 }
708 return params;
709 }
710
711 public FileParams getLegacyFileParams() {
712 FileParams params = new FileParams();
713 if (body == null) {
714 return params;
715 }
716 String parts[] = body.split(",");
717 if (parts.length == 3) {
718 try {
719 params.size = Long.parseLong(parts[0]);
720 } catch (NumberFormatException e) {
721 return null;
722 }
723 try {
724 params.width = Integer.parseInt(parts[1]);
725 } catch (NumberFormatException e) {
726 return null;
727 }
728 try {
729 params.height = Integer.parseInt(parts[2]);
730 } catch (NumberFormatException e) {
731 return null;
732 }
733 return params;
734 } else {
735 return null;
736 }
737 }
738
739 public void untie() {
740 this.mNextMessage = null;
741 this.mPreviousMessage = null;
742 }
743
744 public boolean isFileOrImage() {
745 return type == TYPE_FILE || type == TYPE_IMAGE;
746 }
747
748 public boolean hasFileOnRemoteHost() {
749 return isFileOrImage() && getFileParams().url != null;
750 }
751
752 public boolean needsUploading() {
753 return isFileOrImage() && getFileParams().url == null;
754 }
755
756 public class FileParams {
757 public URL url;
758 public long size = 0;
759 public int width = 0;
760 public int height = 0;
761 }
762
763 public void setAxolotlFingerprint(String fingerprint) {
764 this.axolotlFingerprint = fingerprint;
765 }
766
767 public String getAxolotlFingerprint() {
768 return axolotlFingerprint;
769 }
770
771 public boolean isTrusted() {
772 XmppAxolotlSession.Trust t = conversation.getAccount().getAxolotlService().getFingerprintTrust(axolotlFingerprint);
773 return t != null && t.trusted();
774 }
775
776 private int getPreviousEncryption() {
777 for (Message iterator = this.prev(); iterator != null; iterator = iterator.prev()){
778 if( iterator.isCarbon() || iterator.getStatus() == STATUS_RECEIVED ) {
779 continue;
780 }
781 return iterator.getEncryption();
782 }
783 return ENCRYPTION_NONE;
784 }
785
786 private int getNextEncryption() {
787 for (Message iterator = this.next(); iterator != null; iterator = iterator.next()){
788 if( iterator.isCarbon() || iterator.getStatus() == STATUS_RECEIVED ) {
789 continue;
790 }
791 return iterator.getEncryption();
792 }
793 return conversation.getNextEncryption();
794 }
795
796 public boolean isValidInSession() {
797 int pastEncryption = getCleanedEncryption(this.getPreviousEncryption());
798 int futureEncryption = getCleanedEncryption(this.getNextEncryption());
799
800 boolean inUnencryptedSession = pastEncryption == ENCRYPTION_NONE
801 || futureEncryption == ENCRYPTION_NONE
802 || pastEncryption != futureEncryption;
803
804 return inUnencryptedSession || getCleanedEncryption(this.getEncryption()) == pastEncryption;
805 }
806
807 private static int getCleanedEncryption(int encryption) {
808 if (encryption == ENCRYPTION_DECRYPTED || encryption == ENCRYPTION_DECRYPTION_FAILED) {
809 return ENCRYPTION_PGP;
810 }
811 return encryption;
812 }
813}