Esempio n. 1
0
    def email_signature(self, nodeid, msgid):
        ''' Add a signature to the e-mail with some useful information
        '''
        # simplistic check to see if the url is valid,
        # then append a trailing slash if it is missing
        base = self.db.config.TRACKER_WEB
        if (not isinstance(base , type('')) or
            not (base.startswith('http://') or base.startswith('https://'))):
            web = "Configuration Error: TRACKER_WEB isn't a " \
                "fully-qualified URL"
        else:
            if not base.endswith('/'):
                base = base + '/'
            web = base + self.classname + nodeid

        # ensure the email address is properly quoted
        email = straddr((self.db.config.TRACKER_NAME,
            self.db.config.TRACKER_EMAIL))

        line = '_' * max(len(web)+2, len(email))
        return '\n%s\n%s\n<%s>\n%s'%(line, email, web, line)
Esempio n. 2
0
    def email_signature(self, nodeid, msgid):
        ''' Add a signature to the e-mail with some useful information
        '''
        # simplistic check to see if the url is valid,
        # then append a trailing slash if it is missing
        base = self.db.config.TRACKER_WEB
        if (not isinstance(base, type(''))
                or not (base.startswith('http://')
                        or base.startswith('https://'))):
            web = "Configuration Error: TRACKER_WEB isn't a " \
                "fully-qualified URL"
        else:
            if not base.endswith('/'):
                base = base + '/'
            web = base + self.classname + nodeid

        # ensure the email address is properly quoted
        email = straddr(
            (self.db.config.TRACKER_NAME, self.db.config.TRACKER_EMAIL))

        line = '_' * max(len(web) + 2, len(email))
        return '\n%s\n%s\n<%s>\n%s' % (line, email, web, line)
Esempio n. 3
0
    def send_message(self,
                     nodeid,
                     msgid,
                     note,
                     sendto,
                     from_address=None,
                     bcc_sendto=[]):
        '''Actually send the nominated message from this node to the sendto
           recipients, with the note appended.
        '''
        users = self.db.user
        messages = self.db.msg
        files = self.db.file

        if msgid is None:
            inreplyto = None
            messageid = None
        else:
            inreplyto = messages.get(msgid, 'inreplyto')
            messageid = messages.get(msgid, 'messageid')

        # make up a messageid if there isn't one (web edit)
        if not messageid:
            # this is an old message that didn't get a messageid, so
            # create one
            messageid = "<%s.%s.%s%s@%s>" % (time.time(), random.random(),
                                             self.classname, nodeid,
                                             self.db.config.MAIL_DOMAIN)
            if msgid is not None:
                messages.set(msgid, messageid=messageid)

        # compose title
        cn = self.classname
        title = self.get(nodeid, 'title') or '%s message copy' % cn

        # figure author information
        if msgid:
            authid = messages.get(msgid, 'author')
        else:
            authid = self.db.getuid()
        authname = users.get(authid, 'realname')
        if not authname:
            authname = users.get(authid, 'username', '')
        authaddr = users.get(authid, 'address', '')

        if authaddr and self.db.config.MAIL_ADD_AUTHOREMAIL:
            authaddr = " <%s>" % straddr(('', authaddr))
        elif authaddr:
            authaddr = ""

        # make the message body
        m = ['']

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'top':
            m.append(self.email_signature(nodeid, msgid))

        # add author information
        if authid and self.db.config.MAIL_ADD_AUTHORINFO:
            if msgid and len(self.get(nodeid, 'messages')) == 1:
                m.append(
                    _("New submission from %(authname)s%(authaddr)s:") %
                    locals())
            elif msgid:
                m.append(
                    _("%(authname)s%(authaddr)s added the comment:") %
                    locals())
            else:
                m.append(_("Change by %(authname)s%(authaddr)s:") % locals())
            m.append('')

        # add the content
        if msgid is not None:
            m.append(messages.get(msgid, 'content', ''))

        # get the files for this message
        message_files = []
        if msgid:
            for fileid in messages.get(msgid, 'files'):
                # check the attachment size
                filename = self.db.filename('file', fileid, None)
                filesize = os.path.getsize(filename)
                if filesize <= self.db.config.NOSY_MAX_ATTACHMENT_SIZE:
                    message_files.append(fileid)
                else:
                    base = self.db.config.TRACKER_WEB
                    link = "".join((base, files.classname, fileid))
                    filename = files.get(fileid, 'name')
                    m.append(
                        _("File '%(filename)s' not attached - "
                          "you can download it from %(link)s.") % locals())

        # add the change note
        if note:
            m.append(note)

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'bottom':
            m.append(self.email_signature(nodeid, msgid))

        # encode the content as quoted-printable
        charset = getattr(self.db.config, 'EMAIL_CHARSET', 'utf-8')
        m = '\n'.join(m)
        if charset != 'utf-8':
            m = unicode(m, 'utf-8').encode(charset)
        content = cStringIO.StringIO(m)
        content_encoded = cStringIO.StringIO()
        quopri.encode(content, content_encoded, 0)
        content_encoded = content_encoded.getvalue()

        # make sure the To line is always the same (for testing mostly)
        sendto.sort()

        # make sure we have a from address
        if from_address is None:
            from_address = self.db.config.TRACKER_EMAIL

        # additional bit for after the From: "name"
        from_tag = getattr(self.db.config, 'EMAIL_FROM_TAG', '')
        if from_tag:
            from_tag = ' ' + from_tag

        subject = '[%s%s] %s' % (cn, nodeid, title)
        author = (authname + from_tag, from_address)

        # send an individual message per recipient?
        if self.db.config.NOSY_EMAIL_SENDING != 'single':
            sendto = [[address] for address in sendto]
        else:
            sendto = [sendto]

        # now send one or more messages
        # TODO: I believe we have to create a new message each time as we
        # can't fiddle the recipients in the message ... worth testing
        # and/or fixing some day
        first = True
        for sendto in sendto:
            # create the message
            mailer = Mailer(self.db.config)
            message, writer = mailer.get_standard_message(
                sendto, subject, author)

            # set reply-to to the tracker
            tracker_name = self.db.config.TRACKER_NAME
            if charset != 'utf-8':
                tracker = unicode(tracker_name, 'utf-8').encode(charset)
            tracker_name = encode_header(tracker_name, charset)
            writer.addheader('Reply-To', straddr((tracker_name, from_address)))

            # message ids
            if messageid:
                writer.addheader('Message-Id', messageid)
            if inreplyto:
                writer.addheader('In-Reply-To', inreplyto)

            # Generate a header for each link or multilink to
            # a class that has a name attribute
            for propname, prop in self.getprops().items():
                if not isinstance(prop, (hyperdb.Link, hyperdb.Multilink)):
                    continue
                cl = self.db.getclass(prop.classname)
                if not 'name' in cl.getprops():
                    continue
                if isinstance(prop, hyperdb.Link):
                    value = self.get(nodeid, propname)
                    if value is None:
                        continue
                    values = [value]
                else:
                    values = self.get(nodeid, propname)
                    if not values:
                        continue
                values = [cl.get(v, 'name') for v in values]
                values = ', '.join(values)
                writer.addheader(
                    "X-Roundup-%s-%s" % (self.classname, propname), values)
            if not inreplyto:
                # Default the reply to the first message
                msgs = self.get(nodeid, 'messages')
                # Assume messages are sorted by increasing message number here
                if msgs[0] != nodeid:
                    inreplyto = messages.get(msgs[0], 'messageid')
                    if inreplyto:
                        writer.addheader('In-Reply-To', inreplyto)

            # attach files
            if message_files:
                part = writer.startmultipartbody('mixed')
                part = writer.nextpart()
                part.addheader('Content-Transfer-Encoding', 'quoted-printable')
                body = part.startbody('text/plain; charset=%s' % charset)
                body.write(content_encoded)
                for fileid in message_files:
                    name = files.get(fileid, 'name')
                    mime_type = files.get(fileid, 'type')
                    content = files.get(fileid, 'content')
                    part = writer.nextpart()
                    if mime_type == 'text/plain':
                        part.addheader('Content-Disposition',
                                       'attachment;\n filename="%s"' % name)
                        try:
                            content.decode('ascii')
                        except UnicodeError:
                            # the content cannot be 7bit-encoded.
                            # use quoted printable
                            part.addheader('Content-Transfer-Encoding',
                                           'quoted-printable')
                            body = part.startbody('text/plain')
                            body.write(quopri.encodestring(content))
                        else:
                            part.addheader('Content-Transfer-Encoding', '7bit')
                            body = part.startbody('text/plain')
                            body.write(content)
                    else:
                        # some other type, so encode it
                        if not mime_type:
                            # this should have been done when the file was saved
                            mime_type = mimetypes.guess_type(name)[0]
                        if mime_type is None:
                            mime_type = 'application/octet-stream'
                        part.addheader('Content-Disposition',
                                       'attachment;\n filename="%s"' % name)
                        part.addheader('Content-Transfer-Encoding', 'base64')
                        body = part.startbody(mime_type)
                        body.write(base64.encodestring(content))
                writer.lastpart()
            else:
                writer.addheader('Content-Transfer-Encoding',
                                 'quoted-printable')
                body = writer.startbody('text/plain; charset=%s' % charset)
                body.write(content_encoded)

            if first:
                mailer.smtp_send(sendto + bcc_sendto, message)
            else:
                mailer.smtp_send(sendto, message)
            first = False
Esempio n. 4
0
    def send_message(self, nodeid, msgid, note, sendto, from_address=None,
            bcc_sendto=[]):
        '''Actually send the nominated message from this node to the sendto
           recipients, with the note appended.
        '''
        users = self.db.user
        messages = self.db.msg
        files = self.db.file

        if msgid is None:
            inreplyto = None
            messageid = None
        else:
            inreplyto = messages.get(msgid, 'inreplyto')
            messageid = messages.get(msgid, 'messageid')

        # make up a messageid if there isn't one (web edit)
        if not messageid:
            # this is an old message that didn't get a messageid, so
            # create one
            messageid = "<%s.%s.%s%s@%s>"%(time.time(), random.random(),
                                           self.classname, nodeid,
                                           self.db.config.MAIL_DOMAIN)
            if msgid is not None:
                messages.set(msgid, messageid=messageid)

        # compose title
        cn = self.classname
        title = self.get(nodeid, 'title') or '%s message copy'%cn

        # figure author information
        if msgid:
            authid = messages.get(msgid, 'author')
        else:
            authid = self.db.getuid()
        authname = users.get(authid, 'realname')
        if not authname:
            authname = users.get(authid, 'username', '')
        authaddr = users.get(authid, 'address', '')

        if authaddr and self.db.config.MAIL_ADD_AUTHOREMAIL:
            authaddr = " <%s>" % straddr( ('',authaddr) )
        elif authaddr:
            authaddr = ""

        # make the message body
        m = ['']

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'top':
            m.append(self.email_signature(nodeid, msgid))

        # add author information
        if authid and self.db.config.MAIL_ADD_AUTHORINFO:
            if msgid and len(self.get(nodeid, 'messages')) == 1:
                m.append(_("New submission from %(authname)s%(authaddr)s:")
                    % locals())
            elif msgid:
                m.append(_("%(authname)s%(authaddr)s added the comment:")
                    % locals())
            else:
                m.append(_("Change by %(authname)s%(authaddr)s:") % locals())
            m.append('')

        # add the content
        if msgid is not None:
            m.append(messages.get(msgid, 'content', ''))

        # get the files for this message
        message_files = []
        if msgid :
            for fileid in messages.get(msgid, 'files') :
                # check the attachment size
                filename = self.db.filename('file', fileid, None)
                filesize = os.path.getsize(filename)
                if filesize <= self.db.config.NOSY_MAX_ATTACHMENT_SIZE:
                    message_files.append(fileid)
                else:
                    base = self.db.config.TRACKER_WEB
                    link = "".join((base, files.classname, fileid))
                    filename = files.get(fileid, 'name')
                    m.append(_("File '%(filename)s' not attached - "
                        "you can download it from %(link)s.") % locals())

        # add the change note
        if note:
            m.append(note)

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'bottom':
            m.append(self.email_signature(nodeid, msgid))

        # encode the content as quoted-printable
        charset = getattr(self.db.config, 'EMAIL_CHARSET', 'utf-8')
        m = '\n'.join(m)
        if charset != 'utf-8':
            m = unicode(m, 'utf-8').encode(charset)
        content = cStringIO.StringIO(m)
        content_encoded = cStringIO.StringIO()
        quopri.encode(content, content_encoded, 0)
        content_encoded = content_encoded.getvalue()

        # make sure the To line is always the same (for testing mostly)
        sendto.sort()

        # make sure we have a from address
        if from_address is None:
            from_address = self.db.config.TRACKER_EMAIL

        # additional bit for after the From: "name"
        from_tag = getattr(self.db.config, 'EMAIL_FROM_TAG', '')
        if from_tag:
            from_tag = ' ' + from_tag

        subject = '[%s%s] %s'%(cn, nodeid, title)
        author = (authname + from_tag, from_address)

        # send an individual message per recipient?
        if self.db.config.NOSY_EMAIL_SENDING != 'single':
            sendto = [[address] for address in sendto]
        else:
            sendto = [sendto]

        # now send one or more messages
        # TODO: I believe we have to create a new message each time as we
        # can't fiddle the recipients in the message ... worth testing
        # and/or fixing some day
        first = True
        for sendto in sendto:
            # create the message
            mailer = Mailer(self.db.config)
            message, writer = mailer.get_standard_message(sendto, subject,
                author)

            # set reply-to to the tracker
            tracker_name = self.db.config.TRACKER_NAME
            if charset != 'utf-8':
                tracker = unicode(tracker_name, 'utf-8').encode(charset)
            tracker_name = encode_header(tracker_name, charset)
            writer.addheader('Reply-To', straddr((tracker_name, from_address)))

            # message ids
            if messageid:
                writer.addheader('Message-Id', messageid)
            if inreplyto:
                writer.addheader('In-Reply-To', inreplyto)

            # Generate a header for each link or multilink to
            # a class that has a name attribute
            for propname, prop in self.getprops().items():
                if not isinstance(prop, (hyperdb.Link, hyperdb.Multilink)):
                    continue
                cl = self.db.getclass(prop.classname)
                if not 'name' in cl.getprops():
                    continue
                if isinstance(prop, hyperdb.Link):
                    value = self.get(nodeid, propname)
                    if value is None:
                        continue
                    values = [value]
                else:
                    values = self.get(nodeid, propname)
                    if not values:
                        continue
                values = [cl.get(v, 'name') for v in values]
                values = ', '.join(values)
                writer.addheader("X-Roundup-%s-%s" % (self.classname, propname),
                                 values)
            if not inreplyto:
                # Default the reply to the first message
                msgs = self.get(nodeid, 'messages')
                # Assume messages are sorted by increasing message number here
                if msgs[0] != nodeid:
                    inreplyto = messages.get(msgs[0], 'messageid')
                    if inreplyto:
                        writer.addheader('In-Reply-To', inreplyto)

            # attach files
            if message_files:
                part = writer.startmultipartbody('mixed')
                part = writer.nextpart()
                part.addheader('Content-Transfer-Encoding', 'quoted-printable')
                body = part.startbody('text/plain; charset=%s'%charset)
                body.write(content_encoded)
                for fileid in message_files:
                    name = files.get(fileid, 'name')
                    mime_type = files.get(fileid, 'type')
                    content = files.get(fileid, 'content')
                    part = writer.nextpart()
                    if mime_type == 'text/plain':
                        part.addheader('Content-Disposition',
                            'attachment;\n filename="%s"'%name)
                        try:
                            content.decode('ascii')
                        except UnicodeError:
                            # the content cannot be 7bit-encoded.
                            # use quoted printable
                            part.addheader('Content-Transfer-Encoding',
                                'quoted-printable')
                            body = part.startbody('text/plain')
                            body.write(quopri.encodestring(content))
                        else:
                            part.addheader('Content-Transfer-Encoding', '7bit')
                            body = part.startbody('text/plain')
                            body.write(content)
                    else:
                        # some other type, so encode it
                        if not mime_type:
                            # this should have been done when the file was saved
                            mime_type = mimetypes.guess_type(name)[0]
                        if mime_type is None:
                            mime_type = 'application/octet-stream'
                        part.addheader('Content-Disposition',
                            'attachment;\n filename="%s"'%name)
                        part.addheader('Content-Transfer-Encoding', 'base64')
                        body = part.startbody(mime_type)
                        body.write(base64.encodestring(content))
                writer.lastpart()
            else:
                writer.addheader('Content-Transfer-Encoding',
                    'quoted-printable')
                body = writer.startbody('text/plain; charset=%s'%charset)
                body.write(content_encoded)

            if first:
                mailer.smtp_send(sendto + bcc_sendto, message)
            else:
                mailer.smtp_send(sendto, message)
            first = False