Example #1
0
def kindToMessageObject(mailStamp):
    """
    This method converts an item stamped as MailStamp to an email message
    string
    a Chandler C{MailMessage} object

    @param mailMessage: A Chandler C{MailMessage}
    @type mailMessage: C{MailMessage}

    @return: C{Message.Message}
    """

    view = mailStamp.itsItem.itsView

    mailStampOccurrence, mailStampMaster = getRecurrenceMailStamps(mailStamp)

    isEvent = has_stamp(mailStampOccurrence, EventStamp)
    isTask  = has_stamp(mailStampOccurrence, TaskStamp)

    messageObject = Message.Message()

    # Create a messageId if none exists
    mId = getattr(mailStampMaster, "messageId", None)

    if not mId:
        mId = createMessageID()

    populateHeader(messageObject, 'Message-ID', mId)
    populateEmailAddresses(mailStampMaster, messageObject)
    populateStaticHeaders(messageObject)

    if hasattr(mailStampMaster, "dateSentString"):
        date = mailStampMaster.dateSentString
    else:
        date = datetimeToRFC2822Date(datetime.now(view.tzinfo.default))

    messageObject["Date"] = date

    inReplyTo = getattr(mailStampMaster, "inReplyTo", None)

    subject = mailStampOccurrence.subject

    if subject is not None:
        # Fixes bug 10254 where the title of a Item 
        # that contained a new line was breaking the 
        # the rfc2822 formatting of the outgoing message.
        subject = subject.replace("\n", "")

    if inReplyTo:
        messageObject["In-Reply-To"] = inReplyTo

    if mailStampMaster.referencesMID:
        messageObject["References"] = " ".join(mailStampMaster.referencesMID)

    populateHeader(messageObject, 'Subject', subject, encode=True)

    try:
        payload = getMessageBody(mailStampOccurrence)
    except AttributeError:
        payload = u""

    if not payload:
        # bug 12262, Outlook doesn't like multipart/alternative if there's
        # no payload, so add a few carriage returns to empty bodies
        payload += "\r\n\r\n"

    if isTask or isEvent and payload and \
        not payload.endswith(u"\r\n\r\n"):
        # Chandler outgoing Tasks and Events contain
        # an ics attachment.
        # Many mail readers add attachment icons
        # at the end of the message body.
        # This can be distracting and visually
        # ugly. Appending two line breaks to the
        # payload provides better alignment in
        # mail readers such as Apple Mail and
        # Thunderbird.
        payload += u"\r\n\r\n"

    messageObject.set_type("multipart/mixed")

    # Create a multipart/alernative MIME Part
    # that will contain the Chandler eimml and
    # the body of the message as alternative
    # parts. Doing this prevents users from seeing
    # the Chandler eimml which is machine readable
    # xml code and is not displayable to the user.
    alternative = MIMEMultipart("alternative")

    # Serialize and attach the eimml can raise ConflictsPending
    eimml = outbound(getPeers(mailStampMaster), mailStampMaster.itsItem,
                     OUTBOUND_FILTERS)

    eimmlPayload = MIMEBase64Encode(eimml, 'text', 'eimml')

    # Since alternative parts are in order from least
    # renderable to most renderable add the eimml payload
    # first.
    alternative.attach(eimmlPayload)

    # Attach the body text
    mt = MIMEBase64Encode(payload.encode('utf-8'))

    # Add the email body text to the alternative part
    alternative.attach(mt)

    # Add the alternative part to the mail multipart/mixed
    # main content type.
    messageObject.attach(alternative)


    #XXX There is no attachement support in 1.0
    #hasAttachments = mailStamp.getNumberOfAttachments() > 0

    if isEvent or isTask:
        # Format this message as an ICalendar object
        from osaf.sharing import (serialize, VObjectSerializer,
                                  SharingTranslator, remindersFilter)
        items = [mailStampMaster.itsItem]
        for mod in EventStamp(mailStampMaster).modifications or []:
            if not checkTriageOnly(mod):
                items.append(mod)

        calendar = serialize(mailStamp.itsItem.itsView,
                             items,
                             SharingTranslator,
                             VObjectSerializer,
                             filter=remindersFilter)

        # don't use method REQUEST because it will cause Apple iCal to treat
        # the ics attachment as iMIP
        calendar.add('method').value="PUBLISH"
        ics = calendar.serialize() # returns a UTF-8 encoded str

        # Attach the ICalendar object
        icsPayload = MIMEBase64Encode(ics, 'text', 'calendar', method='PUBLISH')

        # L10N: The filename of Events and Tasks emailed from Chandler
        fname = Header.Header(_(u"ChandlerItem.ics")).encode()
        icsPayload.add_header("Content-Disposition", "attachment", filename=fname)
        messageObject.attach(icsPayload)

    #XXX: There is no attachment support in 1.0 via
    # the MailStamp.mimeContent. Commenting out this code
    # for now.
    #
    #if hasAttachments:
    #    attachments = mailStamp.getAttachments()
    #
    #    for attachment in attachments:
    #        if has_stamp(attachment, MailStamp):
    #            # The attachment is another MailMessage
    #            try:
    #                rfc2822 = binaryToData(MailStamp(attachment).rfc2822Message)
    #            except AttributeError:
    #                rfc2822 = kindToMessageText(attachment, False)
    #
    #            message = email.message_from_string(rfc2822)
    #            rfc2822Payload = MIMEMessage(message)
    #            messageObject.attach(rfc2822Payload)
    #
    #        else:
    #            if isinstance(attachment, MIMEText) and \
    #                attachment.mimeType == u"text/calendar":
    #                icsPayload = MIMENonMultipart('text', 'calendar', \
    #                                    method='REQUEST', _charset="utf-8")
    #
    #                fname = Header.Header(attachment.filename).encode()
    #                icsPayload.add_header("Content-Disposition", "attachment", filename=fname)
    #                icsPayload.set_payload(attachment.data.encode('utf-8'))
    #                messageObject.attach(icsPayload)

    return messageObject
Example #2
0
    def _prepareForSend(self, mailMessageUUID):
        """Sends a mail message via SMTP using the account and mailMessage
           passed to this classes __init__ method using the Twisted Asych Reactor"""

        if __debug__:
            trace("_prepareForSend")

        if self.cancel:
            return self._resetClient()

        # Refresh our view before retrieving Account info
        self.view.refresh()

        self._getAccount()

        # If currently sending a message put the next request in the Queue.
        try:
            # Just in case a cancel was requested after the above cancel check
            # return here instead of seeing if the message should go in the queue
            if self.cancel:
                return self._resetClient()

            msg = self._getMailMessage(mailMessageUUID)
            mailStampOccurrence, masterMailStamp = getRecurrenceMailStamps(msg)

            # The isOnline check is performed in the Twisted thread
            # so pass in a view.
            if self.mailMessage is not None or not Globals.mailService.isOnline(
                    self.view):
                newMessage = masterMailStamp

                try:
                    sending = (self.mailMessage.itsItem is newMessage.itsItem)
                except:
                    sending = False

                inQueue = False

                # Check that the mailMessage in not already Queued
                for item in self.account.messageQueue:
                    if item is newMessage.itsItem:
                        if __debug__:
                            trace(
                                "SMTPClient Queue already contains message: %s"
                                % mailMessageUUID)
                        inQueue = True

                #Sending should always be False in offline mode
                if not inQueue and sending:
                    # Check that the mailMessage in not currently being sent
                    if __debug__:
                        trace("SMTPClient currently sending message: %s" %
                              mailMessageUUID)

                elif not inQueue:
                    self.account.messageQueue.insert(0, newMessage.itsItem)

                    # Update the item state
                    newMessage.itsItem.changeEditState(
                        Modification.queued, who=newMessage.getSender())
                    self.view.commit()

                    if __debug__:
                        trace("SMTPClient adding to the Queue message: %s" %
                              mailMessageUUID)

                # The isOnline check is performed in the Twisted thread
                # so pass in a view.
                if not Globals.mailService.isOnline(self.view):
                    setStatusMessage(constants.UPLOAD_OFFLINE % \
                                    {'accountName': self.account.displayName,
                                     'subject': mailStampOccurrence.subject})

                return

            self.mailMessage = masterMailStamp

            setStatusMessage(constants.UPLOAD_START % \
                             {'accountName': self.account.displayName,
                              'subject': mailStampOccurrence.subject})

            # handles all MailStamp level logic  to support general sending
            # of mail as well as edit / update workflows
            masterMailStamp.outgoingMessage()

            sender = masterMailStamp.getSender()

            # use the individual occurrence, not the master, bug 9499
            messageText = kindToMessageText(mailStampOccurrence)

        except Exception, e:
            if __debug__:
                trace(e)

            return self._mailFailure(e)
Example #3
0
def kindToMessageObject(mailStamp):
    """
    This method converts an item stamped as MailStamp to an email message
    string
    a Chandler C{MailMessage} object

    @param mailMessage: A Chandler C{MailMessage}
    @type mailMessage: C{MailMessage}

    @return: C{Message.Message}
    """

    view = mailStamp.itsItem.itsView

    mailStampOccurrence, mailStampMaster = getRecurrenceMailStamps(mailStamp)

    isEvent = has_stamp(mailStampOccurrence, EventStamp)
    isTask = has_stamp(mailStampOccurrence, TaskStamp)

    messageObject = Message.Message()

    # Create a messageId if none exists
    mId = getattr(mailStampMaster, "messageId", None)

    if not mId:
        mId = createMessageID()

    populateHeader(messageObject, 'Message-ID', mId)
    populateEmailAddresses(mailStampMaster, messageObject)
    populateStaticHeaders(messageObject)

    if hasattr(mailStampMaster, "dateSentString"):
        date = mailStampMaster.dateSentString
    else:
        date = datetimeToRFC2822Date(datetime.now(view.tzinfo.default))

    messageObject["Date"] = date

    inReplyTo = getattr(mailStampMaster, "inReplyTo", None)

    subject = mailStampOccurrence.subject

    if subject is not None:
        # Fixes bug 10254 where the title of a Item
        # that contained a new line was breaking the
        # the rfc2822 formatting of the outgoing message.
        subject = subject.replace("\n", "")

    if inReplyTo:
        messageObject["In-Reply-To"] = inReplyTo

    if mailStampMaster.referencesMID:
        messageObject["References"] = " ".join(mailStampMaster.referencesMID)

    populateHeader(messageObject, 'Subject', subject, encode=True)

    try:
        payload = getMessageBody(mailStampOccurrence)
    except AttributeError:
        payload = u""

    if not payload:
        # bug 12262, Outlook doesn't like multipart/alternative if there's
        # no payload, so add a few carriage returns to empty bodies
        payload += "\r\n\r\n"

    if isTask or isEvent and payload and \
        not payload.endswith(u"\r\n\r\n"):
        # Chandler outgoing Tasks and Events contain
        # an ics attachment.
        # Many mail readers add attachment icons
        # at the end of the message body.
        # This can be distracting and visually
        # ugly. Appending two line breaks to the
        # payload provides better alignment in
        # mail readers such as Apple Mail and
        # Thunderbird.
        payload += u"\r\n\r\n"

    messageObject.set_type("multipart/mixed")

    # Create a multipart/alernative MIME Part
    # that will contain the Chandler eimml and
    # the body of the message as alternative
    # parts. Doing this prevents users from seeing
    # the Chandler eimml which is machine readable
    # xml code and is not displayable to the user.
    alternative = MIMEMultipart("alternative")

    # Serialize and attach the eimml can raise ConflictsPending
    eimml = outbound(getPeers(mailStampMaster), mailStampMaster.itsItem,
                     OUTBOUND_FILTERS)

    eimmlPayload = MIMEBase64Encode(eimml, 'text', 'eimml')

    # Since alternative parts are in order from least
    # renderable to most renderable add the eimml payload
    # first.
    alternative.attach(eimmlPayload)

    # Attach the body text
    mt = MIMEBase64Encode(payload.encode('utf-8'))

    # Add the email body text to the alternative part
    alternative.attach(mt)

    # Add the alternative part to the mail multipart/mixed
    # main content type.
    messageObject.attach(alternative)

    #XXX There is no attachement support in 1.0
    #hasAttachments = mailStamp.getNumberOfAttachments() > 0

    if isEvent or isTask:
        # Format this message as an ICalendar object
        from osaf.sharing import (serialize, VObjectSerializer,
                                  SharingTranslator, remindersFilter)
        items = [mailStampMaster.itsItem]
        for mod in EventStamp(mailStampMaster).modifications or []:
            if not checkTriageOnly(mod):
                items.append(mod)

        calendar = serialize(mailStamp.itsItem.itsView,
                             items,
                             SharingTranslator,
                             VObjectSerializer,
                             filter=remindersFilter)

        # don't use method REQUEST because it will cause Apple iCal to treat
        # the ics attachment as iMIP
        calendar.add('method').value = "PUBLISH"
        ics = calendar.serialize()  # returns a UTF-8 encoded str

        # Attach the ICalendar object
        icsPayload = MIMEBase64Encode(ics,
                                      'text',
                                      'calendar',
                                      method='PUBLISH')

        # L10N: The filename of Events and Tasks emailed from Chandler
        fname = Header.Header(_(u"ChandlerItem.ics")).encode()
        icsPayload.add_header("Content-Disposition",
                              "attachment",
                              filename=fname)
        messageObject.attach(icsPayload)

    #XXX: There is no attachment support in 1.0 via
    # the MailStamp.mimeContent. Commenting out this code
    # for now.
    #
    #if hasAttachments:
    #    attachments = mailStamp.getAttachments()
    #
    #    for attachment in attachments:
    #        if has_stamp(attachment, MailStamp):
    #            # The attachment is another MailMessage
    #            try:
    #                rfc2822 = binaryToData(MailStamp(attachment).rfc2822Message)
    #            except AttributeError:
    #                rfc2822 = kindToMessageText(attachment, False)
    #
    #            message = email.message_from_string(rfc2822)
    #            rfc2822Payload = MIMEMessage(message)
    #            messageObject.attach(rfc2822Payload)
    #
    #        else:
    #            if isinstance(attachment, MIMEText) and \
    #                attachment.mimeType == u"text/calendar":
    #                icsPayload = MIMENonMultipart('text', 'calendar', \
    #                                    method='REQUEST', _charset="utf-8")
    #
    #                fname = Header.Header(attachment.filename).encode()
    #                icsPayload.add_header("Content-Disposition", "attachment", filename=fname)
    #                icsPayload.set_payload(attachment.data.encode('utf-8'))
    #                messageObject.attach(icsPayload)

    return messageObject
Example #4
0
    def _prepareForSend(self, mailMessageUUID):
        """Sends a mail message via SMTP using the account and mailMessage
           passed to this classes __init__ method using the Twisted Asych Reactor"""

        if __debug__:
            trace("_prepareForSend")

        if self.cancel:
            return self._resetClient()

        # Refresh our view before retrieving Account info
        self.view.refresh()

        self._getAccount()

        # If currently sending a message put the next request in the Queue.
        try:
            # Just in case a cancel was requested after the above cancel check
            # return here instead of seeing if the message should go in the queue
            if self.cancel:
                return self._resetClient()

            msg = self._getMailMessage(mailMessageUUID)
            mailStampOccurrence, masterMailStamp = getRecurrenceMailStamps(msg)

            # The isOnline check is performed in the Twisted thread
            # so pass in a view.
            if self.mailMessage is not None or not Globals.mailService.isOnline(self.view):
                newMessage = masterMailStamp

                try:
                    sending = (self.mailMessage.itsItem is newMessage.itsItem)
                except:
                    sending = False

                inQueue = False

                # Check that the mailMessage in not already Queued
                for item in self.account.messageQueue:
                    if item is newMessage.itsItem:
                        if __debug__:
                            trace("SMTPClient Queue already contains message: %s" % mailMessageUUID)
                        inQueue = True

                #Sending should always be False in offline mode
                if not inQueue and sending:
                    # Check that the mailMessage in not currently being sent
                    if __debug__:
                        trace("SMTPClient currently sending message: %s" % mailMessageUUID)

                elif not inQueue:
                    self.account.messageQueue.insert(0, newMessage.itsItem)

                    # Update the item state
                    newMessage.itsItem.changeEditState(Modification.queued,
                                                       who=newMessage.getSender())
                    self.view.commit()

                    if __debug__:
                        trace("SMTPClient adding to the Queue message: %s" % mailMessageUUID)

                # The isOnline check is performed in the Twisted thread
                # so pass in a view.
                if not Globals.mailService.isOnline(self.view):
                    setStatusMessage(constants.UPLOAD_OFFLINE % \
                                    {'accountName': self.account.displayName,
                                     'subject': mailStampOccurrence.subject})

                return

            self.mailMessage = masterMailStamp

            setStatusMessage(constants.UPLOAD_START % \
                             {'accountName': self.account.displayName,
                              'subject': mailStampOccurrence.subject})

            # handles all MailStamp level logic  to support general sending
            # of mail as well as edit / update workflows
            masterMailStamp.outgoingMessage()

            sender = masterMailStamp.getSender()

            # use the individual occurrence, not the master, bug 9499
            messageText = kindToMessageText(mailStampOccurrence)

        except Exception, e:
            if __debug__:
                trace(e)

            return self._mailFailure(e)