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 18import logging 19 20from nbxmpp.namespaces import Namespace 21from nbxmpp.protocol import NodeProcessed 22from nbxmpp.protocol import InvalidFrom 23from nbxmpp.protocol import InvalidStanza 24from nbxmpp.protocol import Message 25from nbxmpp.structs import MAMData 26from nbxmpp.structs import CarbonData 27from nbxmpp.modules.delay import parse_delay 28 29 30log = logging.getLogger('nbxmpp.m.misc') 31 32 33def unwrap_carbon(stanza, own_jid): 34 carbon = stanza.getTag('received', namespace=Namespace.CARBONS) 35 if carbon is None: 36 carbon = stanza.getTag('sent', namespace=Namespace.CARBONS) 37 if carbon is None: 38 return stanza, None 39 40 # Carbon must be from our bare jid 41 if stanza.getFrom() != own_jid.new_as_bare(): 42 raise InvalidFrom('Invalid from: %s' % stanza.getAttr('from')) 43 44 forwarded = carbon.getTag('forwarded', namespace=Namespace.FORWARD) 45 message = Message(node=forwarded.getTag('message')) 46 47 type_ = carbon.getName() 48 49 # Fill missing to/from 50 to = message.getTo() 51 if to is None: 52 message.setTo(own_jid.bare) 53 54 frm = message.getFrom() 55 if frm is None: 56 message.setFrom(own_jid.bare) 57 58 if type_ == 'received': 59 if message.getFrom().bare_match(own_jid): 60 # Drop 'received' Carbons from ourself, we already 61 # got the message with the 'sent' Carbon or via the 62 # message itself 63 raise NodeProcessed('Drop "received"-Carbon from ourself') 64 65 if message.getTag('x', namespace=Namespace.MUC_USER) is not None: 66 # A MUC broadcasts messages sent to us to all resources 67 # there is no need to process the received carbon 68 raise NodeProcessed('Drop MUC-PM "received"-Carbon') 69 70 return message, CarbonData(type=type_) 71 72 73def unwrap_mam(stanza, own_jid): 74 result = stanza.getTag('result', namespace=Namespace.MAM_2) 75 if result is None: 76 result = stanza.getTag('result', namespace=Namespace.MAM_1) 77 if result is None: 78 return stanza, None 79 80 query_id = result.getAttr('queryid') 81 if query_id is None: 82 log.warning('No queryid on MAM message') 83 log.warning(stanza) 84 raise InvalidStanza 85 86 id_ = result.getAttr('id') 87 if id_ is None: 88 log.warning('No id on MAM message') 89 log.warning(stanza) 90 raise InvalidStanza 91 92 forwarded = result.getTag('forwarded', namespace=Namespace.FORWARD) 93 message = Message(node=forwarded.getTag('message')) 94 95 # Fill missing to/from 96 to = message.getTo() 97 if to is None: 98 message.setTo(own_jid.bare) 99 100 frm = message.getFrom() 101 if frm is None: 102 message.setFrom(own_jid.bare) 103 104 # Timestamp parsing 105 # Most servers dont set the 'from' attr, so we cant check for it 106 delay_timestamp = parse_delay(forwarded) 107 if delay_timestamp is None: 108 log.warning('No timestamp on MAM message') 109 log.warning(stanza) 110 raise InvalidStanza 111 112 return message, MAMData(id=id_, 113 query_id=query_id, 114 archive=stanza.getFrom(), 115 namespace=result.getNamespace(), 116 timestamp=delay_timestamp) 117 118 119def build_xhtml_body(xhtml, xmllang=None): 120 try: 121 if xmllang is not None: 122 body = '<body xmlns="%s" xml:lang="%s">%s</body>' % ( 123 Namespace.XHTML, xmllang, xhtml) 124 else: 125 body = '<body xmlns="%s">%s</body>' % (Namespace.XHTML, xhtml) 126 except Exception as error: 127 log.error('Error while building xhtml node: %s', error) 128 return None 129 return body 130