1# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com> 2# 3# This file is part of nbxmpp. 4# 5# This program is free software; you can redistribute it and/or 6# modify it under the terms of the GNU General Public License 7# as published by the Free Software Foundation; either version 3 8# of the License, or (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; If not, see <http://www.gnu.org/licenses/>. 17 18from nbxmpp.namespaces import Namespace 19from nbxmpp.protocol import isMucPM 20from nbxmpp.protocol import Message 21from nbxmpp.structs import StanzaHandler 22from nbxmpp.structs import ReceiptData 23from nbxmpp.util import generate_id 24from nbxmpp.modules.base import BaseModule 25 26 27class Receipts(BaseModule): 28 def __init__(self, client): 29 BaseModule.__init__(self, client) 30 31 self._client = client 32 self.handlers = [ 33 StanzaHandler(name='message', 34 callback=self._process_message_receipt, 35 ns=Namespace.RECEIPTS, 36 priority=15), 37 ] 38 39 def _process_message_receipt(self, _client, stanza, properties): 40 request = stanza.getTag('request', namespace=Namespace.RECEIPTS) 41 if request is not None: 42 properties.receipt = ReceiptData(request.getName()) 43 return 44 45 received = stanza.getTag('received', namespace=Namespace.RECEIPTS) 46 if received is not None: 47 id_ = received.getAttr('id') 48 if id_ is None: 49 self._log.warning('Receipt without id attr') 50 self._log.warning(stanza) 51 return 52 53 properties.receipt = ReceiptData(received.getName(), id_) 54 55 56def build_receipt(stanza): 57 if not isinstance(stanza, Message): 58 raise ValueError('Stanza type must be protocol.Message') 59 60 if stanza.getType() == 'error': 61 raise ValueError('Receipt can not be generated for type error messages') 62 63 if stanza.getID() is None: 64 raise ValueError('Receipt can not be generated for messages without id') 65 66 if stanza.getTag('received', namespace=Namespace.RECEIPTS) is not None: 67 raise ValueError('Receipt can not be generated for receipts') 68 69 is_muc_pm = isMucPM(stanza) 70 71 jid = stanza.getFrom() 72 typ = stanza.getType() 73 if typ == 'groupchat' or not is_muc_pm: 74 jid = jid.new_as_bare() 75 76 message = Message(to=jid, typ=typ) 77 if is_muc_pm: 78 message.setTag('x', namespace=Namespace.MUC_USER) 79 message_id = generate_id() 80 message.setID(message_id) 81 message.setReceiptReceived(stanza.getID()) 82 message.setHint('store') 83 message.setOriginID(message_id) 84 return message 85