def __init__(self, owner):
     self._APP_ID = app_identity.get_application_id()
     self._owner = owner
     self._communications = Communications()
     self._messageLog = MemCacheCircularBuffer(owner.logSize, "xmppVoiceMailLog")
class XmppVoiceMail:
    """
    Represents a virtual cell phone, which can receive SMS messages and voicemail.
    """
    def __init__(self, owner):
        self._APP_ID = app_identity.get_application_id()
        self._owner = owner
        self._communications = Communications()
        self._messageLog = MemCacheCircularBuffer(owner.logSize, "xmppVoiceMailLog")

    def _log(self, direction, contact, message):
        if isinstance(contact, Contact):
            contact = contact.name
            
        logItem = LogItem(direction, contact, message)
        self._messageLog.addItem(logItem)

    def getLog(self):
        return self._messageLog.getItems()

    def handleIncomingCall(self, fromNumber, callStatus):
        """Handle an incoming call.
        """
        displayFrom = toPrettyNumber(fromNumber)
        
        # Find the XMPP user to send this from
        contact = Contact.getByPhoneNumber(fromNumber)
        if contact:
            displayFrom = contact.name
        else:
            contact = Contact.getDefaultSender()
            
        self.sendMessageToOwner("Call from: " + displayFrom + " status:" + callStatus, contact, fromNumber)

    def getDisplayNameAndContact(self, number):
        displayName = toPrettyNumber(number)
        
        # Find the XMPP user to send this from
        contact = Contact.getByPhoneNumber(number)
        if contact:
            displayName = contact.name
        else:
            contact = Contact.getDefaultSender()
            
        return (displayName, contact)
        

    def handleVoiceMail(self, fromNumber, transcriptionText=None, recordingUrl=None):
        """Handle an incoming voice mail.
        """
        displayName, contact = self.getDisplayNameAndContact(fromNumber)

        body = "New message from " + displayName
        if transcriptionText:
            body += ": " + transcriptionText
            
        if recordingUrl:
            body += " - Recording: " + recordingUrl
            
        self._log(LogItem.TO_OWNER, displayName, body)
        return self.sendMessageToOwner(body, contact, fromNumber)

    def handleIncomingSms(self, fromNumber, toNumber, body):
        """Handle an incoming SMS message from the network.
        """

        # Find the XMPP user to send this from
        displayName, contact = self.getDisplayNameAndContact(fromNumber)
        
        self._log(LogItem.TO_OWNER, displayName, body)
            
        # Forward the message to the owner
        self.sendMessageToOwner(body, contact, fromNumber)

    def handleIncomingXmpp(self, sender, to, messageBody):
        """Handle an incoming XMPP message from the owner.
        
        Raises InvalidParametersException if there are problems with the incoming XMPP message.
        Raises PermissionException if the sender is not authorized to use this service.
        Raises SmsException if an SMS cannot be sent for this email.
        """
        # Make sure the message is from the owner, to stop third parties from
        # using this to spam.
        if not sender == self._owner.jid:
            raise PermissionException("Incorrect XMPP user")

        self._forwardToSms(to, messageBody)

    def handleIncomingEmail(self, sender, to, subject, messageBody):
        """Handle an incoming Email message from the owner.
        
        Raises InvalidParametersException if there are any problems with the format of the email.
        Raises PermissionException if the sender is not authorized to use this service.
        Raises SmsException if an SMS cannot be sent for this email.
        """
        if not self._owner.emailEnabled():
            raise PermissionException("Email Disabled.")

        if not self._owner.emailAddress in sender:
            raise PermissionException("Incorrect user")
        
        self._forwardToSms(to, messageBody)

    def _forwardToSms(self, to, messageBody):
        toName = to.split("@")[0]

        contact = Contact.getByName(toName)
        if not contact:
            raise InvalidParametersException("Unknown contact " + toName)
    
        toNumber, body = self._getNumberAndBody(contact, messageBody)

        self._communications.sendSMS(self._owner.phoneNumber, toNumber, body)
        
        self._log(LogItem.FROM_OWNER, contact, body)

            


    def sendXmppInvite(self, nickname):
        """Send an XMPP invite to the owner of this phone for the given nickname.
        """
        if self._owner.xmppEnabled():
            fromJid = nickname + "@" + self._APP_ID + ".appspotchat.com"
            self._communications.sendXmppInvite(fromJid, self._owner.jid)

    _messageRegex = re.compile(r"^([^:]*):(.*)$")

    def _getNumberAndBody(self, contact, body):
        """Get the destination contact and the message body from a message.
        
        The message will be either to the default sender, in which case
        the body will be of the format "number:message", or else the message
        will be to a nickname, and the body will just be the message.

        This returns the tuple (toNumber, body), where toNumber
        is the SMS number to send this message to, and body is the message
        content.
        
        Raises InvalidParametersException if there are any errors in the input.
        """
        
        if not contact.isDefaultSender():
            toNumber = contact.normalizedPhoneNumber
            
        else:
            # Parse the phone number and body out of the message
            match = self._messageRegex.match(body)
            if not match:
                raise InvalidParametersException("Use 'number:message' to send an SMS.")

            toNumber = match.group(1)
            if not validateNumber(toNumber):
                raise InvalidParametersException("Invalid number: " + match.group(1))

            toNumber = toNormalizedNumber(toNumber)
            body = match.group(2).strip()
                    
        return (toNumber, body)


    def _ownerXmppPresent(self, fromJid):
        xmppOnline = False
        if self._owner.xmppEnabled():
            if self._owner.jid.endswith("@gmail.com"):
                # This always shows the user online in the dev environment, so fall back on the DB for dev.
                xmppOnline = self._communications.getXmppPresence(self._owner.jid, fromJid)
            else:
                user = XmppUser.getByJid(self._owner.jid)
                if user:
                    xmppOnline = user.presence
                
        return xmppOnline
    
    def sendMessageToOwner(self, message, contact=None, fromNumber=None):
        """
        Send a message to the user who owns this XmppVoiceMail account.

        contact is the contact to send the message from.
        
        fromNumber is the phone number to send the message from if contact is
        the default sender.

        Returns True on success, False on failure.
        """
        answer = False

        defaultSender = Contact.getDefaultSender()
        if not contact:
            contact = defaultSender

        fromJid = contact.name  + "@" + self._APP_ID + ".appspotchat.com"
        xmppOnline = self._ownerXmppPresent(fromJid)
                
        sendByEmail = self._owner.emailEnabled() and ( (not xmppOnline) or \
                      ((not contact.subscribed) and (not defaultSender.subscribed)) ) 
                
        if sendByEmail:
            self.sendEmailMessageToOwner(
                subject=message,
                fromContact=contact,
                fromNumber=fromNumber)
            answer = True
             
        elif self._owner.xmppEnabled():
            if not contact.subscribed:
                # Need a subscribed contact for XMPP; use the default sender.
                contact = defaultSender

            result = self._sendXMPPMessage(
                message=message,
                fromContact=contact,
                fromNumber=fromNumber)
            answer = result == xmpp.NO_ERROR
                
        return answer


    def _sendXMPPMessage(self, message, fromContact=None, fromNumber=None):
        if not fromContact:
            fromContact = Contact.getDefaultSender()

        # Add the fromNumber to the message if this is from the default sender.
        if fromContact.isDefaultSender() and fromNumber:
            message = toPrettyNumber(fromNumber) + ": " + message

        logging.debug("Sending XMPP message to " + self._owner.jid + ": " + message)

        fromJid = fromContact.name + "@" + self._APP_ID + ".appspotchat.com"
        return self._communications.sendXmppMessage(fromJid, self._owner.jid, message)


    def sendEmailMessageToOwner(self, subject, body=None, fromContact=None, fromNumber=None):
        if not body:
            body = ""

        if not fromContact:
            fromContact = Contact.getDefaultSender()

        fromName = fromContact.name
        if fromNumber:
            fromAddress = stripNumber(toNormalizedNumber(fromNumber))
        elif not fromContact.isDefaultSender():
            fromContact.normalizedPhoneNumber
        else:
            fromAddress = fromName
            
        logging.debug("Sending eMail message to " + self._owner.emailAddress + ": " + subject)

        fromAddress = '"' + fromName + '" <' + fromAddress + "@" + self._APP_ID + ".appspotmail.com>"
        self._communications.sendMail(
            sender=fromAddress,
            to=self._owner.emailAddress,
            subject=subject,
            body=body)

    def sendSMS(self, contact, toNumber, body):
        """ Send an SMS message,
        
        'contact' is only used for display purposes in the log, and may be passed as None.
        
        Logs message sent, and any errors which happen as a result of sending it.
        
        Raises SmsException on send error.
        """
        displayName = contact
        if not contact:
            displayName, contact = self.getDisplayNameAndContact(toNumber)
            
        self._log(LogItem.FROM_OWNER, displayName, body)
        try:
            self._communications.sendSMS(self._owner.phoneNumber, toNumber, body)
        except SmsException as e:
            self._log(LogItem.TO_OWNER, displayName, "Could not send message: " + e.value)