/** * Copyright (c) 2013, Redsolution LTD. All rights reserved. * * This file is part of Xabber project; you can redistribute it and/or * modify it under the terms of the GNU General Public License, Version 3. * * Xabber 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 General Public License for more details. * * You should have received a copy of the GNU General Public License, * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.xabber.android.data.message; import com.xabber.android.data.Application; import com.xabber.android.data.NetworkException; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.connection.ConnectionItem; import com.xabber.android.data.connection.StanzaSender; import com.xabber.android.data.connection.listeners.OnPacketListener; import com.xabber.android.data.database.MessageDatabaseManager; import com.xabber.android.data.database.messagerealm.MessageItem; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.log.LogManager; import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.receipts.DeliveryReceipt; import org.jivesoftware.smackx.receipts.DeliveryReceiptManager; import org.jivesoftware.smackx.receipts.DeliveryReceiptRequest; import org.jivesoftware.smackx.receipts.ReceiptReceivedListener; import org.jxmpp.jid.Jid; import io.realm.Realm; /** * Manage message receive receipts as well as error replies. * * @author alexander.ivanov */ public class ReceiptManager implements OnPacketListener, ReceiptReceivedListener { private static ReceiptManager instance; static { // TODO: change to ifSubscribed when isSubscribedToMyPresence will work and problem with thread element will be solved DeliveryReceiptManager.setDefaultAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.disabled); } public static ReceiptManager getInstance() { if (instance == null) { instance = new ReceiptManager(); } return instance; } private ReceiptManager() { XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { @Override public void connectionCreated(final XMPPConnection connection) { DeliveryReceiptManager.getInstanceFor(connection).addReceiptReceivedListener(ReceiptManager.this); DeliveryReceiptManager.getInstanceFor(connection).autoAddDeliveryReceiptRequests(); } }); } @Override public void onStanza(ConnectionItem connection, Stanza packet) { if (!(connection instanceof AccountItem)) { return; } final AccountJid account = ((AccountItem) connection).getAccount(); final Jid from = packet.getFrom(); if (from == null) { return; } if (!(packet instanceof Message)) { return; } final Message message = (Message) packet; if (message.getType() == Message.Type.error) { Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { markAsError(account, message); } }); } else { // TODO setDefaultAutoReceiptMode should be used for (ExtensionElement packetExtension : message.getExtensions()) { if (packetExtension instanceof DeliveryReceiptRequest) { String id = message.getStanzaId(); if (id == null) { continue; } Message receipt = new Message(from); receipt.addExtension(new DeliveryReceipt(id)); // the key problem is Thread - smack does not keep it in auto reply receipt.setThread(message.getThread()); try { StanzaSender.sendStanza(account, receipt); } catch (NetworkException e) { LogManager.exception(this, e); } } } } } private void markAsError(final AccountJid account, final Message message) { Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); realm.beginTransaction(); MessageItem first = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.ACCOUNT, account.toString()) .equalTo(MessageItem.Fields.STANZA_ID, message.getStanzaId()).findFirst(); if (first != null) { first.setError(true); } realm.commitTransaction(); realm.close(); EventBus.getDefault().post(new MessageUpdateEvent(account)); } @Override public void onReceiptReceived(Jid fromJid, final Jid toJid, final String receiptId, Stanza stanza) { DeliveryReceipt receipt = DeliveryReceipt.from((Message) stanza); if (receipt == null) { return; } markAsDelivered(toJid, receiptId); } private void markAsDelivered(final Jid toJid, final String receiptId) { Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm(); realm.beginTransaction(); MessageItem first = realm.where(MessageItem.class) .equalTo(MessageItem.Fields.STANZA_ID, receiptId).findFirst(); if (first != null) { first.setDelivered(true); } realm.commitTransaction(); realm.close(); EventBus.getDefault().post(new MessageUpdateEvent()); } }