PgpDecryptionService.java

  1package eu.siacs.conversations.crypto;
  2
  3import android.app.PendingIntent;
  4
  5import eu.siacs.conversations.entities.Message;
  6import eu.siacs.conversations.services.XmppConnectionService;
  7import eu.siacs.conversations.ui.UiCallback;
  8
  9import java.util.Collections;
 10import java.util.LinkedList;
 11import java.util.List;
 12import java.util.concurrent.ConcurrentHashMap;
 13
 14public class PgpDecryptionService {
 15
 16	private final XmppConnectionService xmppConnectionService;
 17	private final ConcurrentHashMap<String, List<Message>> messages = new ConcurrentHashMap<>();
 18	private final ConcurrentHashMap<String, Boolean> decryptingMessages = new ConcurrentHashMap<>();
 19	private Boolean keychainLocked = false;
 20	private final Object keychainLockedLock = new Object();
 21
 22	public PgpDecryptionService(XmppConnectionService xmppConnectionService) {
 23		this.xmppConnectionService = xmppConnectionService;
 24	}
 25
 26	public void add(Message message) {
 27		if (isRunning()) {
 28			decryptDirectly(message);
 29		} else {
 30			store(message);
 31		}
 32	}
 33
 34	public void addAll(List<Message> messagesList) {
 35		if (!messagesList.isEmpty()) {
 36			String conversationUuid = messagesList.get(0).getConversation().getUuid();
 37			if (!messages.containsKey(conversationUuid)) {
 38				List<Message> list = Collections.synchronizedList(new LinkedList<Message>());
 39				messages.put(conversationUuid, list);
 40			}
 41			synchronized (messages.get(conversationUuid)) {
 42				messages.get(conversationUuid).addAll(messagesList);
 43			}
 44			decryptAllMessages();
 45		}
 46	}
 47
 48	public void onKeychainUnlocked() {
 49		synchronized (keychainLockedLock) {
 50			keychainLocked = false;
 51		}
 52		decryptAllMessages();
 53	}
 54
 55	public void onKeychainLocked() {
 56		synchronized (keychainLockedLock) {
 57			keychainLocked = true;
 58		}
 59		xmppConnectionService.updateConversationUi();
 60	}
 61
 62	public void onOpenPgpServiceBound() {
 63		decryptAllMessages();
 64	}
 65
 66	public boolean isRunning() {
 67		synchronized (keychainLockedLock) {
 68			return !keychainLocked;
 69		}
 70	}
 71
 72	private void store(Message message) {
 73		if (messages.containsKey(message.getConversation().getUuid())) {
 74			messages.get(message.getConversation().getUuid()).add(message);
 75		} else {
 76			List<Message> messageList = Collections.synchronizedList(new LinkedList<Message>());
 77			messageList.add(message);
 78			messages.put(message.getConversation().getUuid(), messageList);
 79		}
 80	}
 81
 82	private void decryptAllMessages() {
 83		for (String uuid : messages.keySet()) {
 84			decryptMessages(uuid);
 85		}
 86	}
 87
 88	private void decryptMessages(final String uuid) {
 89		synchronized (decryptingMessages) {
 90			Boolean decrypting = decryptingMessages.get(uuid);
 91			if ((decrypting != null && !decrypting) || decrypting == null) {
 92				decryptingMessages.put(uuid, true);
 93				decryptMessage(uuid);
 94			}
 95		}
 96	}
 97
 98	private void decryptMessage(final String uuid) {
 99		Message message = null;
100		synchronized (messages.get(uuid)) {
101			while (!messages.get(uuid).isEmpty()) {
102				if (messages.get(uuid).get(0).getEncryption() == Message.ENCRYPTION_PGP) {
103					if (isRunning()) {
104						message = messages.get(uuid).remove(0);
105					}
106					break;
107				} else {
108					messages.get(uuid).remove(0);
109				}
110			}
111			if (message != null && xmppConnectionService.getPgpEngine() != null) {
112				xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback<Message>() {
113
114					@Override
115					public void userInputRequried(PendingIntent pi, Message message) {
116						messages.get(uuid).add(0, message);
117						decryptingMessages.put(uuid, false);
118					}
119
120					@Override
121					public void success(Message message) {
122						xmppConnectionService.updateConversationUi();
123						decryptMessage(uuid);
124					}
125
126					@Override
127					public void error(int error, Message message) {
128						message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
129						xmppConnectionService.updateConversationUi();
130						decryptMessage(uuid);
131					}
132				});
133			} else {
134				decryptingMessages.put(uuid, false);
135			}
136		}
137	}
138
139	private void decryptDirectly(final Message message) {
140		if (message.getEncryption() == Message.ENCRYPTION_PGP && xmppConnectionService.getPgpEngine() != null) {
141			xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback<Message>() {
142
143				@Override
144				public void userInputRequried(PendingIntent pi, Message message) {
145					store(message);
146				}
147
148				@Override
149				public void success(Message message) {
150					xmppConnectionService.updateConversationUi();
151					xmppConnectionService.getNotificationService().updateNotification(false);
152				}
153
154				@Override
155				public void error(int error, Message message) {
156					message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
157					xmppConnectionService.updateConversationUi();
158				}
159			});
160		}
161	}
162}