def parse(self, message, nofragment=False): otrTagPos = message.find(proto.OTRTAG) if otrTagPos == -1: if proto.MESSAGE_TAG_BASE in message: return proto.TaggedPlaintext.parse(message) else: return message indexBase = otrTagPos + len(proto.OTRTAG) if len(message) <= indexBase: return message compare = message[indexBase] if nofragment is False and compare == b','[0]: message = self.fragmentAccumulate(message[indexBase:]) if message is None: return None else: return self.parse(message, nofragment=True) else: self.discardFragment() queryPayload = self.parseExplicitQuery(message) if queryPayload is not None: return proto.Query.parse(queryPayload) if compare == b':'[0] and len(message) > indexBase + 4: try: infoTag = base64.b64decode(message[indexBase + 1:indexBase + 5]) classInfo = struct.unpack(b'!HB', infoTag) cls = proto.messageClasses.get(classInfo, None) if cls is None: return message logger.debug('{user} got msg {typ!r}' \ .format(user=self.user.name, typ=cls)) return cls.parsePayload(message[indexBase + 5:]) except (TypeError, struct.error): logger.exception('could not parse OTR message %s', message) return message if message[indexBase:indexBase + 7] == b' Error:': return proto.Error(message[indexBase + 7:]) return message
def receiveMessage(self, messageData, appdata=None): IGN = None, [] if not self.policyOtrEnabled(): raise NotOTRMessage(messageData) message = self.parse(messageData) if message is None: # nothing to see. move along. return IGN logger.debug(repr(message)) if self.getPolicy('SEND_TAG'): if isinstance(message, basestring): # received a plaintext message without tag # we should not tag anymore self.tagOffer = OFFER_REJECTED else: # got something OTR-ish, cool! self.tagOffer = OFFER_ACCEPTED if isinstance(message, proto.Query): self.handleQuery(message, appdata=appdata) if isinstance(message, proto.TaggedPlaintext): # it's actually a plaintext message if self.state != STATE_PLAINTEXT or \ self.getPolicy('REQUIRE_ENCRYPTION'): # but we don't want plaintexts raise UnencryptedMessage(message.msg) raise NotOTRMessage(message.msg) return IGN if isinstance(message, proto.AKEMessage): self.crypto.handleAKE(message, appdata=appdata) return IGN if isinstance(message, proto.DataMessage): ignore = message.flags & proto.MSGFLAGS_IGNORE_UNREADABLE if self.state != STATE_ENCRYPTED: self.sendInternal(proto.Error( 'You sent encrypted data, but I wasn\'t expecting it.' .encode('utf-8')), appdata=appdata) if ignore: return IGN raise NotEncryptedError(EXC_UNREADABLE_MESSAGE) try: plaintext, tlvs = self.crypto.handleDataMessage(message) self.processTLVs(tlvs, appdata=appdata) if plaintext and self.lastSend < time() - HEARTBEAT_INTERVAL: self.sendInternal(b'', appdata=appdata) return plaintext or None, tlvs except crypt.InvalidParameterError: if ignore: return IGN logger.exception('decryption failed') raise if isinstance(message, basestring): if self.state != STATE_PLAINTEXT or \ self.getPolicy('REQUIRE_ENCRYPTION'): raise UnencryptedMessage(message) if isinstance(message, proto.Error): raise ErrorReceived(message) raise NotOTRMessage(messageData)