summaryrefslogtreecommitdiff
path: root/slixmpp/plugins/xep_0184/receipt.py
blob: 2c3555dcc38e584c1f88fc510997c7c74ed5b53c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""
    Slixmpp: The Slick XMPP Library
    Copyright (C) 2012 Erik Reuterborg Larsson, Nathanael C. Fritz
    This file is part of Slixmpp.

    See the file LICENSE for copying permission.
"""

import logging

from slixmpp.stanza import Message
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins import BasePlugin
from slixmpp.plugins.xep_0184 import stanza, Request, Received


class XEP_0184(BasePlugin):

    """
    XEP-0184: Message Delivery Receipts
    """

    name = 'xep_0184'
    description = 'XEP-0184: Message Delivery Receipts'
    dependencies = set(['xep_0030'])
    stanza = stanza
    default_config = {
        'auto_ack': True,
        'auto_request': False
    }

    ack_types = ('normal', 'chat', 'headline')

    def plugin_init(self):
        register_stanza_plugin(Message, Request)
        register_stanza_plugin(Message, Received)

        self.xmpp.add_filter('out', self._filter_add_receipt_request)

        self.xmpp.register_handler(
                Callback('Message Receipt',
                    StanzaPath('message/receipt'),
                    self._handle_receipt_received))

        self.xmpp.register_handler(
                Callback('Message Receipt Request',
                    StanzaPath('message/request_receipt'),
                    self._handle_receipt_request))

    def plugin_end(self):
        self.xmpp['xep_0030'].del_feature('urn:xmpp:receipts')
        self.xmpp.del_filter('out', self._filter_add_receipt_request)
        self.xmpp.remove_handler('Message Receipt')
        self.xmpp.remove_handler('Message Receipt Request')

    def session_bind(self, jid):
        self.xmpp['xep_0030'].add_feature('urn:xmpp:receipts')

    def ack(self, msg):
        """
        Acknowledge a message by sending a receipt.

        Arguments:
            msg -- The message to acknowledge.
        """
        ack = self.xmpp.Message()
        ack['to'] = msg['from']
        ack['receipt'] = msg['id']
        ack.send()

    def _handle_receipt_received(self, msg):
        self.xmpp.event('receipt_received', msg)

    def _handle_receipt_request(self, msg):
        """
        Auto-ack message receipt requests if ``self.auto_ack`` is ``True``.

        Arguments:
            msg -- The incoming message requesting a receipt.
        """
        if self.auto_ack:
            if msg['type'] in self.ack_types:
                if not msg['receipt']:
                    self.ack(msg)

    def _filter_add_receipt_request(self, stanza):
        """
        Auto add receipt requests to outgoing messages, if:

            - ``self.auto_request`` is set to ``True``
            - The message is not for groupchat
            - The message does not contain a receipt acknowledgment
            - The recipient is a bare JID or, if a full JID, one
              that has the ``urn:xmpp:receipts`` feature enabled

        The disco cache is checked if a full JID is specified in
        the outgoing message, which may mean a round-trip disco#info
        delay for the first message sent to the JID if entity caps
        are not used.
        """

        if not self.auto_request:
            return stanza

        if not isinstance(stanza, Message):
            return stanza

        if stanza['request_receipt']:
            return stanza

        if not stanza['type'] in self.ack_types:
            return stanza

        if stanza['receipt']:
            return stanza

        if not stanza['body']:
            return stanza

        if stanza['to'].resource:
            if not self.xmpp['xep_0030'].supports(stanza['to'],
                    feature='urn:xmpp:receipts',
                    cached=True):
                return stanza

        stanza['request_receipt'] = True
        return stanza