/** * Copyright (C) 2013 Open WhisperSystems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.whispersystems.textsecuregcm.push; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.entities.ApnMessage; import org.whispersystems.textsecuregcm.entities.CryptoEncodingException; import org.whispersystems.textsecuregcm.entities.EncryptedOutgoingMessage; import org.whispersystems.textsecuregcm.entities.GcmMessage; import org.whispersystems.textsecuregcm.push.WebsocketSender.DeliveryStatus; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Device; import static org.whispersystems.textsecuregcm.entities.MessageProtos.OutgoingMessageSignal; public class PushSender { private final Logger logger = LoggerFactory.getLogger(PushSender.class); private static final String APN_PAYLOAD = "{\"aps\":{\"sound\":\"default\",\"badge\":%d,\"alert\":{\"loc-key\":\"APN_Message\"}}}"; private final PushServiceClient pushServiceClient; private final WebsocketSender webSocketSender; public PushSender(PushServiceClient pushServiceClient, WebsocketSender websocketSender) { this.pushServiceClient = pushServiceClient; this.webSocketSender = websocketSender; } public void sendMessage(Account account, Device device, OutgoingMessageSignal message) throws NotPushRegisteredException, TransientPushFailureException { if (device.getGcmId() != null) sendGcmMessage(account, device, message); else if (device.getApnId() != null) sendApnMessage(account, device, message); else if (device.getFetchesMessages()) sendWebSocketMessage(account, device, message); else throw new NotPushRegisteredException("No delivery possible!"); } public WebsocketSender getWebSocketSender() { return webSocketSender; } private void sendGcmMessage(Account account, Device device, OutgoingMessageSignal message) throws TransientPushFailureException, NotPushRegisteredException { try { String number = account.getNumber(); long deviceId = device.getId(); String registrationId = device.getGcmId(); boolean isReceipt = message.getType() == OutgoingMessageSignal.Type.RECEIPT_VALUE; EncryptedOutgoingMessage encryptedMessage = new EncryptedOutgoingMessage(message, device.getSignalingKey()); GcmMessage gcmMessage = new GcmMessage(registrationId, number, (int) deviceId, encryptedMessage.toEncodedString(), isReceipt); pushServiceClient.send(gcmMessage); } catch (CryptoEncodingException e) { throw new NotPushRegisteredException(e); } } private void sendApnMessage(Account account, Device device, OutgoingMessageSignal outgoingMessage) throws TransientPushFailureException { DeliveryStatus deliveryStatus = webSocketSender.sendMessage(account, device, outgoingMessage, true); if (!deliveryStatus.isDelivered() && outgoingMessage.getType() != OutgoingMessageSignal.Type.RECEIPT_VALUE) { ApnMessage apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), (int)device.getId(), String.format(APN_PAYLOAD, deliveryStatus.getMessageQueueDepth())); pushServiceClient.send(apnMessage); } } private void sendWebSocketMessage(Account account, Device device, OutgoingMessageSignal outgoingMessage) { webSocketSender.sendMessage(account, device, outgoingMessage, false); } }